<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://wiki-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Asellali</id>
	<title>wiki-se.plil.fr - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Asellali"/>
	<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php/Sp%C3%A9cial:Contributions/Asellali"/>
	<updated>2026-05-14T04:02:32Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=3322</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=3322"/>
		<updated>2023-12-06T14:30:53Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Menu de la première séance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui Mohammed&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Blgrim Haitam&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Konstantin PATRIKEEV&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Karl HABRE&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Rémi FARAULT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en PRA ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| Elom|| || || Baloo|| || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| Mustafar (Mustafare)|| || mustafare.lol|| Baloo|| 193.48.57.189|| Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| Dagobah|| || || Aladin|| || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| Motis|| || || Dingo|| || Mohammed Halaoui&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| bogano|| || || Timon|| || Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| Takobo|| || || Timon|| 193.48.57.184|| Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| Fondor|| || || mushu|| 193.48.57.190|| Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| hoth|| || || BlancheNeige|| 193.48.57.187|| Haitam Blgrim&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| Abafar|| || abafar.lol|| Aladin|| 193.48.57.179|| Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| Rotia|| || || DIngo|| 193.48.57.181|| Rémi Farault&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| jedha|| || || judy|| 193.48.57.182|| Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| Bogden|| || || BlancheNeige|| || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| || || || || 193.48.57.188|| Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| jiruus|| || || cruella|| || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| exegol|| || || cruella|| 193.48.57.186|| Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| Jakku|| || || Jafar|| || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| naboo|| 192.168.18.2|| naboo.lol|| bouh|| 193.48.57.180 / 192.168.18.1|| Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| geonosis|| || geonosis.lol|| bouh|| || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| alderaan|| || || Jafar|| 193.48.57.183|| Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| kesh|| || || Judy|| || Konstantin Patrikeev&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| kashyyyk|| || || mushu|| || Maxime BALBASTRE&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| Felucia|| || || || 193.48.57.185|| François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| Pelagon|| || || || || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 20/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
A noter qu'aucune machine, quelle soit de service ou mandataire, ne peut avoir accès à Internet vu qu'aucun effort n'a été fait pour relier le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; au réseau SE5.&lt;br /&gt;
&lt;br /&gt;
Machines de service.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy || une seule interface dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; (CV SE5), aucun CV privé, pas de configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT || || rien&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Liste des machines&lt;br /&gt;
&lt;br /&gt;
 Elom Mustafar dagobah Motis bogano Takobo Fondor hoth abafar Rotia jedha Bogden jiruus exegol Jakku naboo geonosis alderaan kesh kashyyyk Felucia&lt;br /&gt;
&lt;br /&gt;
 Baloo aladin Dingo Timon mushu BlancheNeige cruella Jafar bouh judy&lt;br /&gt;
&lt;br /&gt;
=== Contrôle du 03/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; a été relié au réseau SE5 par &amp;lt;code&amp;gt;naboo&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Il est normal de ne pas avoir d'adresse IPv4 sur la machine de services pour l'interface sur le commutateur virtuel. Par contre, avec mise en place de la mascarade sur la machine mandataire, il doit être possible, pour la machine de services, de se connecter à Internet en IPv4.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elève !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elom || Elias SIMON&lt;br /&gt;
| IPv4 sur CV : 10.0.69.220, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0f:b26d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Mustafar|| Mathis RIFFAUT&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fea9:f79, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Dagobah|| Dann RODENBURG&lt;br /&gt;
| IPv4 sur CV : 10.0.69.205, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe53:7d33, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Motis || Mohammed Halaoui&lt;br /&gt;
| IPv4 sur CV : 10.0.69.195, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7c:2d6a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| bogano || Benjamin Nguyen&lt;br /&gt;
| IPv4 sur CV : 10.0.69.245, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe62:6960, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Takobo || Timothé Brenier&lt;br /&gt;
| IPv4 sur CV : 10.0.69.181, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe93:8c48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Fondor || Florian Vallée&lt;br /&gt;
| IPv4 sur CV : 10.0.69.200, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2d:82bf, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| hoth || Haitam Blgrim&lt;br /&gt;
| IPv4 sur CV : 10.0.69.157, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee8:4736, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle &lt;br /&gt;
|-&lt;br /&gt;
| Abafar || Amine SELLALI&lt;br /&gt;
| IPv4 sur CV : 10.0.69.233, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feae:bcbb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Rotia || Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe2e:ec48, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| jedha || Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.221, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef6:364f, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Bogden || Black Baptiste&lt;br /&gt;
| IPv4 sur CV : 10.0.69.246, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe67:89fd, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| jiruus || Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.247, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe9c:6f0e, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| exegol || Estelle Godard&lt;br /&gt;
| IPv4 sur CV : 10.0.69.147, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe17:bc38, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jakku || Jason DELANNOY&lt;br /&gt;
| IPv4 sur CV : 10.0.69.136, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee1:1e4d, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| naboo || Chloé Lemaire&lt;br /&gt;
| IPv4 sur CV : 192.168.18.2, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fef2:7e2, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| geonosis || Gabriel THOMAS&lt;br /&gt;
| IPv4 sur CV : 10.0.69.231, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feb0:b140, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| alderaan || Albin MOUTON&lt;br /&gt;
| IPv4 sur CV : 10.0.69.106, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe97:2114, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| kesh || Konstantin Patrikeev&lt;br /&gt;
| IPv4 sur CV : 10.0.69.222, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe10:e2cb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| kashyyyk || Maxime BALBASTRE&lt;br /&gt;
| IPv4 sur CV : 10.0.69.240, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feca:73e7, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Felucia || François NAUDOT&lt;br /&gt;
| IPv4 sur CV : 10.0.69.139, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe89:460a, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Machines mandataires.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Elèves !! Nom machine !! Configuration IP&lt;br /&gt;
|-&lt;br /&gt;
| Elias SIMON &amp;amp; Mathis RIFFAUT || Baloo &lt;br /&gt;
| IPv4 sur CV : 10.0.69.152, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fec8:5379, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Dann RODENBURG &amp;amp; Amine SELLALI || Aladin&lt;br /&gt;
| IPv4 sur CV : 10.0.69.107, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe6b:c000, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Mohammed Halaoui &amp;amp; Rémi Farault || Dingo&lt;br /&gt;
| IPv4 sur CV : 10.0.69.156, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe0d:4f9c, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Benjamin Nguyen &amp;amp; Timothé Brenier || Timon&lt;br /&gt;
| IPv4 sur CV : 10.0.69.104, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fedc:7539, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Florian Vallée &amp;amp; Maxime BALBASTRE || mushu&lt;br /&gt;
| IPv4 sur CV : 10.0.69.160, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe20:8816, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Haitam Blgrim &amp;amp; Black Baptiste || BlancheNeige&lt;br /&gt;
| IPv4 sur CV : 10.0.69.182, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:feba:38f4, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jeanne Delcourt &amp;amp; Estelle Godard || cruella&lt;br /&gt;
| IPv4 sur CV : 10.0.69.108, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fee5:ff99, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Jason DELANNOY &amp;amp; Albin MOUTON || Jafar&lt;br /&gt;
| IPv4 sur CV : 10.0.69.171, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe3e:f0bb, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Chloé Lemaire &amp;amp; Gabriel THOMAS || bouh&lt;br /&gt;
| IPv4 sur CV : 192.168.18.1, IPv4 sur SE5 : 193.48.57.180, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe4f:dde2, connexion à Internet en IPv4 possible, connexion à Internet en IPv6 possible, résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| Konstantin Patrikeev &amp;amp; Julien Charleux || judy&lt;br /&gt;
| IPv4 sur CV : 10.0.69.216, pas d'IPv4 sur SE5, IPv6 sur SE5 : 2001:660:4401:60b0:216:3eff:fe7d:4762, pas de connexion à Internet en IPv4, connexion à Internet en IPv6 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
|-&lt;br /&gt;
| François NAUDOT || &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en ASR ==&lt;br /&gt;
&lt;br /&gt;
Donnez les élèves dans chaque groupe.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves &lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux &lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros &lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton &lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut &lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali &lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault &lt;br /&gt;
|-&lt;br /&gt;
|g13&lt;br /&gt;
|Maxime Balbastre &amp;amp; Florian Vallée&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Le 05/11/2023, aucun commutateur virtuel correctement configuré, soit une adresse IPv4 sur le commutateur pour aucune raison, soit une configuration &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt; non adaptée, pas de &amp;lt;code&amp;gt;up&amp;lt;/code&amp;gt; sur le commutateur virtuel.&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 05/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Migration !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || || jcharleu, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || kpatrikee, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || || gthomas, CV conf. erronée, MV mdp erroné, interf. vlan50 || clemair1, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, une seule interface réseau, pas de config. réseau&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || || bnguyen1, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || tbrenier, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || || drodenbu, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || fnaudot, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur mauvais disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || || pas de CV, pas de MV || mdelaby, CV conf. erronée, pygrub dans la MV ? pas de routeur, faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || || hblgrim, CV conf. erronée, MV avec 2 interfaces, pas de MAC sur la 1ère, config. IPv4 OK || bblack, CV commenté, pas de MV (plus exactement une machine visible via &amp;lt;code&amp;gt;xen list&amp;lt;/code&amp;gt; mais pas de &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;/etc/xen&amp;lt;/code&amp;gt;), pas de routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || || jdelanno, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || amouton, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, une seule interface réseau&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || || mriffaut, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || esimon, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, pas de routeur&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || || jdelcour, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || egodard, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur lancé, deux interfaces réseau, changez l'ordre des interfaces dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || || khabre, CV conf. erronée, MV non créée, MV interf. vlan50, pas de config. IPv4 || asellali, CV conf. erronée, MV interf. vlan50, pas de config. IPv4, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || || rfarault, CV conf. erronée, MV interf. vlan50, pas de config. IPv4 || pas de CV, MV interf. vlan50, pas de config. IPv4, pas de routeur&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 20/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
A noter qu'un sacré coup de pouce aura été nécessaire pour configurer le routeur de promotion, avec un seul élève en appui.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Migration !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || || jcharleu, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || kpatrikee, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || || gthomas, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || clemair1, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4, routeur lancé et correctement configuré&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || || bnguyen1, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || tbrenier, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || || drodenbu, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || fnaudot, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || || toujours pas de CV, pas de VLAN, toujours pas de MV || mdelaby, CV configuration toujours erronée, pas de VLAN, toujours le bootloader &amp;lt;code&amp;gt;pygrub&amp;lt;/code&amp;gt; dans la MV (commenté), MV avec une seule interface réseau (dans le CV), configuration DHCP OK pour l'interface (dans le CV), toujours pas de routeur : il faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || || hblgrim, CV conf. toujours erronée, pas de VLAN, MV ne démarre pas à cause de l'erreur sur le CV (correction ReX sur le CV), MV avec 2 interfaces, pas de MAC sur la première interface dans le .cfg, configuration IPv4 OK dans la MV || bblack, CV configuration toujours erronée, pas de VLAN, toujours pas e &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; pour la MV, un routeur OpenWRT avec la bonne définition de disque, deux interface mais sans @MAC, aucune configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || || jdelanno, CV conf. toujours, erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte || amouton, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, une seule interface réseau, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || || mriffaut, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || esimon, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || || jdelcour, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || egodard, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, deux interfaces réseau, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || || khabre, CV conf. toujours erronée, pas de VLAN, MV enfin créée avec une seule interface, pas de configuration IPv4 correcte || asellali, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, une seule interface, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || || rfarault, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte || pas de CV, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 30/11/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! Archi. penfret !! Archi. antifer&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux || jcharleu, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || kpatrikee, CV et VLAN configurés mais dites moi comment vous trouvez 1 avec la formule &amp;lt;code&amp;gt;6+N%4&amp;lt;/code&amp;gt;, MV avec les bonnes interfaces, inversion dans la configuration IPv4 entre &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;enX1&amp;lt;/code&amp;gt;, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; par contre les deux interfaces demandées sont présentes.&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas || gthomas, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4. || clemair1, CV configuré, VLAN configuré, MV lancée et totalement configurée en IPv4, routeur lancé et correctement configuré.&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen || bnguyen1, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || tbrenier, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant.&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg || drodenbu, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte. || fnaudot, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, pour le routeur toujours une mauvaise définition de disque dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, deux interfaces cependant.&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros || toujours pas de CV, pas de VLAN, toujours pas de MV. || mdelaby, CV configuration toujours erronée, pas de VLAN, toujours le bootloader &amp;lt;code&amp;gt;pygrub&amp;lt;/code&amp;gt; dans la MV (commenté), MV avec un chemin des disques étranges, MV avec une seule interface réseau (dans le CV), configuration DHCP OK pour l'interface (dans le CV), toujours pas de routeur : il faut lui créer son propre &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black || hblgrim, il manque les directives pour démarrer et arrêter les interfaces mais sinon CV et VLAN configurés, MV lancé et configurée, il ne faut pas de &amp;lt;code&amp;gt;gateway&amp;lt;/code&amp;gt; sur &amp;lt;code&amp;gt;enX1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son adresse par DHCP à cause du commutateur virtuel non activé. || bblack, CV et VLAN configurés mais pas toutes les directives de démarrage et d'arrêt, toujours pas de &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; pour la MV, un routeur OpenWRT avec la bonne définition de disque, deux interface mais sans @MAC, aucune configuration du routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton || jdelanno, CV conf. toujours, erronée, pas de VLAN, MV avec une seule interface (vlan50), toujours pas de configuration IPv4 correcte; || amouton, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur lancé, une seule interface réseau, pas de configuration du routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut || mriffaut, CV conf. toujours erronée, pas de VLAN, MV avec une seule interface (vlan50), pas de configuration IPv4 correcte. || esimon, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, toujours pas de routeur.&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt || jdelcour, CV configuré, VLAN configuré (par contre l'utilisation de &amp;lt;code&amp;gt;ether4&amp;lt;/code&amp;gt; est impossible), MV lancée et correctement configurée en IPv4, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son @IPv4 à cause de l'erreur sur le VLAN. || egodard, CV configuré, VLAN configuré (par contre l'utilisation de &amp;lt;code&amp;gt;ether4&amp;lt;/code&amp;gt; est impossible), MV avec deux interfaces, correctement configurée en IPv4, pas d'adresse obtenue par DHCP, problème de l'OpenWRT, routeur OpenWRT avec les bonnes interfaces, l'adresse IPv4 sur SE5 est donnée avec un mauvais masque, linterface &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; reçoit bien son adresse IPv4 par DHCP.&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali || khabre, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface, pas de configuration IPv4 correcte || asellali, CV configuration toujours erronée, pas de VLAN, MV avec une seule interface réseau (dans le vlan50), pas de configuration IPv4 correcte, routeur avec une définition de disque aberrante dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, une seule interface, pas de configuration du routeur&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault || rfarault, CV configuré, VLAN configuré mais configuration commentée (pourquoi donc ?!), MV lancée et correctement configurée en IPv4, &amp;lt;code&amp;gt;enX0&amp;lt;/code&amp;gt; ne trouve pas son @IPv4 à cause de l'absence d'interface VLAN. || CV configuré, VLAN configuré, MV avec deux interfaces, correctement configurée en IPv4, un routeur avec les deux interfaces demandées, pas d'adresse IPv4 sur SE5, serveur DHCP fonctionnel.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 02/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! MV &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; !! MV &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; !! Routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet, une IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
| IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.180, une IPv6 routée sur Internet, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel (si ? non, inversion des &amp;lt;code&amp;gt;vif&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| image disque du fichier de configuration non présente sur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt;&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas de fichier de configuration&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le fichier de configuration&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.116, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe01:754c, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| routeur openWRT non fonctionnel&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.191, une IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali&lt;br /&gt;
| MV non contactable sur le VLAN 50 en IPv6&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le fichier de configuration, création du routeur impossible&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet, pas d'IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 05/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Pour utiliser l'interface Web LuCi des openWRT à partir d'une zabeth :&lt;br /&gt;
* vérifiez que vous avez bien une IPv6 routée sur IPv6 (avec &amp;lt;code&amp;gt;ip address show dev eth0&amp;lt;/code&amp;gt;, l'adresse commence par &amp;lt;code&amp;gt;2001:660:4401:60b0:&amp;lt;/code&amp;gt;) ;&lt;br /&gt;
* si vous n'en avez pas, prenez le suffixe (les derniers 8 octets de l'adresse locale, celle qui commence par &amp;lt;code&amp;gt;fe80::&amp;lt;/code&amp;gt;) et créez votre adresse IPv6 routée par la commande :&lt;br /&gt;
  ip address add dev eth0 2001:660:4401:60b0:&amp;lt;suffixe&amp;gt;/64&lt;br /&gt;
bien entendu vous n'aurez oublié de rajouter la route IPv6 par défaut vers le routeur de la promotion :&lt;br /&gt;
  ip -6 route add default via 2001:660:4401:60b0:6a9e:bff:fe46:5a76&lt;br /&gt;
* établissez un tunnel &amp;lt;code&amp;gt;ssh&amp;lt;/code&amp;gt; avec la commande :&lt;br /&gt;
 zabethXX# ssh -L 6443:localhost:6443 root@IPv6&lt;br /&gt;
* connectez vous sur LuCi avec le navigateur de la zabeth pointant sur &amp;lt;code&amp;gt;https://localhost:6443&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attention l'ordre des interfaces &amp;lt;code&amp;gt;vif&amp;lt;/code&amp;gt; dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt; a une importance.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves !! MV &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; !! MV &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; !! Routeur OpenWRT&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux&lt;br /&gt;
| IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 routée sur Internet (puis &amp;lt;code&amp;gt;193.48.57.191&amp;lt;/code&amp;gt; donc une erreur), pas d'IPv6 routée sur Internet, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
| IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.180, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe31:b916, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen &lt;br /&gt;
| IPv4 sur CV : 10.0.69.130, IPv4 sur VLAN50 : 172.26.145.107, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feff:4c44, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.167, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.184, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feaa:f293, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g4 || François Naudot &amp;amp; Dann Rodenburg &lt;br /&gt;
| IPv4 sur CV : 10.0.69.156, IPv4 sur VLAN50 : 172.26.145.109, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe46:70cd, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.106, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.185, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fec6:169, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Maël Delaby &amp;amp; Paul Amoros&lt;br /&gt;
| IPv4 sur CV : 10.0.69.189, IPv4 sur VLAN50 : 172.26.145.111, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe14:cdb5, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.171, IPv4 sur VLAN50 : 172.26.145.110, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe5b:b2b5, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.188, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe5b:b2b6, connexion à Internet en IPv4 possible&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black &lt;br /&gt;
| IPv4 sur CV : 10.0.69.100, IPv4 sur VLAN50 : 172.26.145.113, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fef9:2bb9, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas de machine virtuelle&lt;br /&gt;
| bloquage du serveur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; par installation du routeur openWRT sous la racine, machine non contactable en IPv6 sur le SE5&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton&lt;br /&gt;
| CV non configuré, machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudent&lt;br /&gt;
| pas d'adresse MAC dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g8 || Elias Simon &amp;amp; Mathis Riffaut&lt;br /&gt;
| CV non configuré, machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| machine non contactable en IPv6 sur le SE5&lt;br /&gt;
|-&lt;br /&gt;
| g10 || Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
| IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.191 (erreur !!), IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feb4:5ea4, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
| g11 || Karl Habre &amp;amp; Amine Sellali&lt;br /&gt;
| machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
| machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
| pas d'adresse MAC dans le &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| g12 || Mohammed Halaoui &amp;amp; Rémi Farault&lt;br /&gt;
| IPv4 sur CV : 10.0.69.131, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
| IPv4 sur Internet : 193.48.57.181, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Pas de changement sur les routeurs OpenWRT à 17h30.&lt;br /&gt;
&lt;br /&gt;
Pas de changement sur les MV d'&amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; à 18h00.&lt;br /&gt;
&lt;br /&gt;
Une seule modification sur les MV de &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; à 18h15 : la G7 (&amp;lt;code&amp;gt;g7jdelannoVM&amp;lt;/code&amp;gt;) est maintenant contactable (@IPv4 et @IPv6 sur le VLAN50) mais sans rien de plus.&lt;br /&gt;
&lt;br /&gt;
=== Contrôle au 06/12/2023 ===&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les routeurs openWRT (pas de relancement) :&lt;br /&gt;
&lt;br /&gt;
 G1 | IPv4 sur Internet : 193.48.57.191, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4&lt;br /&gt;
 G2 | IPv4 sur Internet : 193.48.57.180, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe31:b916, connexion à Internet en IPv4 possible&lt;br /&gt;
 G3 | IPv4 sur Internet : 193.48.57.184, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feaa:f293, connexion à Internet en IPv4 possible&lt;br /&gt;
 G4 | IPv4 sur Internet : 193.48.57.185, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fec6:169, connexion à Internet en IPv4 possible&lt;br /&gt;
 G5 | IPv4 sur Internet : 193.48.57.188, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe5b:b2b6, connexion à Internet en IPv4 possible&lt;br /&gt;
 G6 | IPv4 sur Internet : 193.48.57.187, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fef9:2bba, connexion à Internet en IPv4 possible&lt;br /&gt;
 G7 | Bad MAC address &lt;br /&gt;
 G8 | machine non contactable en IPv6 sur le SE5&lt;br /&gt;
 G9 | Rien&lt;br /&gt;
 G10 | IPv4 sur Internet : 193.48.57.186, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:feb4:5ea4, pas de connexion à Internet en IPv4&lt;br /&gt;
 G11 | machine non contactable en IPv6 sur le SE5&lt;br /&gt;
 G12 | IPv4 sur Internet : 193.48.57.181, IPv6 sur Internet : 2001:660:4401:60b0:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les MV sur &amp;lt;code&amp;gt;antifer&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 ==== g1kpatrikeevVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.218, IPv4 sur VLAN50 : 172.26.145.102, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7d:bc44, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g2clemair1VM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.145, IPv4 sur VLAN50 : 172.26.145.104, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe31:b916, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g3tbrenierVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.167, IPv4 sur VLAN50 : 172.26.145.106, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feaa:f292, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g4fnaudotVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.106, IPv4 sur VLAN50 : 172.26.145.108, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fec6:168, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g5mdelabyVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.171, IPv4 sur VLAN50 : 172.26.145.110, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe5b:b2b5, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g6bblackVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.113, IPv4 sur VLAN50 : 172.26.145.112, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe4a:d2be, connexion à Internet en IPv4 possible, resolution DNS fonctionnelle&lt;br /&gt;
 ==== g7amoutonVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.114, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe59:7616, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g8esimonVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
 ==== g10egodardVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.132, IPv4 sur VLAN50 : 172.26.145.120, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feb4:5ea3, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g11asellaliVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le bridgeStudents&lt;br /&gt;
 ==== g12mhalaouiVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.124, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe9a:5186, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
&lt;br /&gt;
Données brutes pour les MV sur &amp;lt;code&amp;gt;penfret&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 ==== g1jcharleuxVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.185, IPv4 sur VLAN50 : 172.126.145.103, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe00:a98d, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g2gthomasVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.212, IPv4 sur VLAN50 : 172.26.145.105, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fedb:2ac4, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g3bnguyen1VM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.130, IPv4 sur VLAN50 : 172.26.145.107, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:feff:4c44, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
 ==== g4drodenbuVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.156, IPv4 sur VLAN50 : 172.26.145.109, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe46:70cd, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g5pamorosVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.189, IPv4 sur VLAN50 : 172.26.145.111, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe14:cdb5, connexion à Internet en IPv4 possible, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g6hblgrimVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.100, IPv4 sur VLAN50 : 172.26.145.113, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fef9:2bb9, connexion à Internet en IPv4 possible, résolution DNS fonctionnelle&lt;br /&gt;
 ==== g7jdelannoVM&lt;br /&gt;
 | pas d'IPv4 sur le CV, IPv4 sur VLAN50 : 172.26.145.115, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe0f:aba1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g8mriffautVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
 ==== g10jdelcourVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.165, IPv4 sur VLAN50 : 172.26.145.121, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe7e:35e1, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;br /&gt;
 ==== g11khabreVM&lt;br /&gt;
 | machine non contactable en IPv6 sur le VLAN50&lt;br /&gt;
 ==== g12rfaraultVM&lt;br /&gt;
 | IPv4 sur CV : 10.0.69.131, IPv4 sur VLAN50 : 172.26.145.125, IPv6 sur VLAN50 : 2001:660:4401:6050:216:3eff:fe54:5aee, pas de connexion à Internet en IPv4, pas de résolution DNS fonctionnelle&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=2068</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=2068"/>
		<updated>2023-10-16T12:44:49Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Répartition des binômes en ASR */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui mohammed et rémi farault(absent)&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Blgrim Haitam&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Konstantin PATRIKEEV&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Karl HABRE&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en PRA ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| Elom|| || || Baloo|| || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| Mustafar|| || || Baloo|| || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| Dagobah|| || || Aladin|| || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| Motis|| || || Dingo|| || mohammed halaoui&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| bogano|| || || Timon|| || Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| Takobo|| || || Timon|| || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| Fondor|| || || mushu|| || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| hoth|| || || BlancheNeige|| || Haitam Blgrim&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| Abafar|| || || Aladin|| || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| Rotia|| || || DIngo|| || Rémi farault&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| jedha|| || || judy|| || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| Bogden|| || || BlancheNeige|| || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| jiruus|| || || cruella|| || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| exegol|| || || cruella|| || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| Jakku|| || || Jafar|| || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| naboo|| || || bouh|| || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| geonosis|| || || bouh|| || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| alderaan|| || || Jafar|| || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| kesh|| || || Judy|| || Konstantin Patrikeev&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| kashyyyk|| || || mushu|| || Maxime BALBASTRE&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| Felucia|| || || || || François NAUDOT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes en ASR ==&lt;br /&gt;
&lt;br /&gt;
Donnez les élèves dans chaque groupe.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Groupe !! Elèves&lt;br /&gt;
|-&lt;br /&gt;
| g1 || Konstantin Patrikeev &amp;amp; Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| g2 || Chloé Lemaire &amp;amp; Gabriel Thomas&lt;br /&gt;
|-&lt;br /&gt;
| g3 || Timothé Brenier &amp;amp; Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| g4 || Dann Rodenburg &amp;amp; François Naudot&lt;br /&gt;
|-&lt;br /&gt;
| g5 || Delaby Maël &amp;amp; Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| g6 || Haitam Blgrim &amp;amp; Baptiste Black&lt;br /&gt;
|-&lt;br /&gt;
| g7 || Jason Delannoy &amp;amp; Albin Mouton&lt;br /&gt;
|-&lt;br /&gt;
|g8&lt;br /&gt;
|Elias Simon &amp;amp; Mathis Riffaut&lt;br /&gt;
|-&lt;br /&gt;
|g10&lt;br /&gt;
|Estelle Godard &amp;amp; Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
|g11&lt;br /&gt;
|Karl Habre &amp;amp; Amine Sellali&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1945</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1945"/>
		<updated>2023-10-06T15:10:30Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Répartition des binômes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui mohammed&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Blgrim Haitam&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| Elom|| || || Baloo|| || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| Mustafar|| || || Baloo|| || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| Dagobah|| || || Aladin|| || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| bogano|| || || Timon|| || Benjamin Nguyen&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| Takobo|| || || Timon|| || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| Fondor|| || || mushu|| || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| Abafar|| || || Aladin|| || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| Bogden|| || || BlancheNeige|| || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| jiruus|| || || cruella|| || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| exegol|| || || cruella|| || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| Jakku|| || || Jafar|| || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| naboo|| || || bouh|| || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| geonosis|| || || bouh|| || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| alderaan|| || || Jafar|| || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| kashyyyk|| || || mushu|| || Maxime BALBASTRE&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1924</id>
		<title>SE5 système/réseau 2023/2024</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE5_syst%C3%A8me/r%C3%A9seau_2023/2024&amp;diff=1924"/>
		<updated>2023-10-06T14:16:27Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Menu de la première séance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PRA SE5 =&lt;br /&gt;
&lt;br /&gt;
== Menu de la première séance ==&lt;br /&gt;
&lt;br /&gt;
Pour la  première séance du 06/10/2023 il vous est demandé d'effectuer individuellement les opérations listées ci-dessous.&lt;br /&gt;
* création d'une machine virtuelle sur le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* création d'un conteneur &amp;quot;à la main&amp;quot; sur votre station de travail &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; :&lt;br /&gt;
** créez un conteneur isolé au maximum (sauf pour les utilisateur) avec la méthode décrite en cours,&lt;br /&gt;
** création d'un commutateur virtuel privé sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt; dans le réseau IPv4 &amp;lt;code&amp;gt;192.168.68.0/24&amp;lt;/code&amp;gt;, l'adresse &amp;lt;code&amp;gt;192.168.68.1&amp;lt;/code&amp;gt; est affectée au commutateur lui-même,&lt;br /&gt;
** création d'une interface Ethernet virtuelle, une extrémité doit être envoyée dans le conteneur, l'autre dans le commutateur virtuel privé,&lt;br /&gt;
** mise en place d'une mascarade sur la &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;, vérifiez que le conteneur a accès aux mêmes machines que la  &amp;lt;code&amp;gt;zabeth&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Par binôme vous devez créer une machine virtuelle mandataire connectée sur le commutateur virtuel SE5 et sur le commutateur virtuel privé des machines virtuelles de services concernées (voir deuxième section du sujet).&lt;br /&gt;
&lt;br /&gt;
Globalement vous devez configurer le routeur principal de la promotion (voir la troisième section du sujet). Pour votre promotion il s'agit du Catalyst 9200 situé en E304. Il faut le connecter en fibre vers le serveur &amp;lt;code&amp;gt;capbreton&amp;lt;/code&amp;gt; de la E306 dans le commutateur virtuel SE5 et aussi en fibre vers le local technique SR52 sur un port dans le VLAN 531. Vous pouvez configurer le commutateur via l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt; à partir de la machine &amp;lt;code&amp;gt;zabeth09&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Répartition des élèves pour la première séance :&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Station de travail !! Elève&lt;br /&gt;
|-&lt;br /&gt;
| zabeth02 || Elias SIMON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth03 || Mathis RIFFAUT&lt;br /&gt;
|-&lt;br /&gt;
| zabeth04 || Dann RODENBURG&lt;br /&gt;
|-&lt;br /&gt;
| zabeth05 || Benjamin NGUYEN&lt;br /&gt;
|-&lt;br /&gt;
| zabeth06 || Halaoui mohammed&lt;br /&gt;
|-&lt;br /&gt;
| zabeth07 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth08 || Florian Vallée&lt;br /&gt;
|-&lt;br /&gt;
| zabeth09 (routeur) || Julien Charleux&lt;br /&gt;
|-&lt;br /&gt;
| zabeth10 || Amine SELLALI&lt;br /&gt;
|-&lt;br /&gt;
| zabeth11 || Paul Amoros&lt;br /&gt;
|-&lt;br /&gt;
| zabeth12 || Maël Delaby&lt;br /&gt;
|-&lt;br /&gt;
| zabeth13 || Black Baptiste&lt;br /&gt;
|-&lt;br /&gt;
| zabeth14 || Timothé Brenier&lt;br /&gt;
|-&lt;br /&gt;
| zabeth15 || Jeanne Delcourt&lt;br /&gt;
|-&lt;br /&gt;
| zabeth16 || Estelle Godard&lt;br /&gt;
|-&lt;br /&gt;
| zabeth17 || Jason DELANNOY&lt;br /&gt;
|-&lt;br /&gt;
| zabeth18 || Chloé Lemaire&lt;br /&gt;
|-&lt;br /&gt;
| zabeth19 || Gabriel THOMAS&lt;br /&gt;
|-&lt;br /&gt;
| zabeth20 || Albin MOUTON&lt;br /&gt;
|-&lt;br /&gt;
| zabeth21 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth22 || Maxime Balbastre&lt;br /&gt;
|-&lt;br /&gt;
| zabeth26 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth27 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth28 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| zabeth30 || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Répartition des binômes ==&lt;br /&gt;
&lt;br /&gt;
Concertez-vous pour trouver des noms de machines de services et de machines mandataires dans deux thèmes.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cahier !! Nom machine services &lt;br /&gt;
!IP machine services !! Nom de domaine !! Nom machine mandataire &lt;br /&gt;
!IP machine mandataires!! Elève &lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E1 | Cahier n°1]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E2 | Cahier n°2]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E3 | Cahier n°3]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E4 | Cahier n°4]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E5 | Cahier n°5]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E6 | Cahier n°6]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E7 | Cahier n°7]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E8 | Cahier n°8]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E9 | Cahier n°9]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E10 | Cahier n°10]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E11 | Cahier n°11]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E12 | Cahier n°12]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E13 | Cahier n°13]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E14 | Cahier n°14]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E15 | Cahier n°15]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E16 | Cahier n°16]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E17 | Cahier n°17]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E18 | Cahier n°18]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E19 | Cahier n°19]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E20 | Cahier n°20]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E21 | Cahier n°21]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E22 | Cahier n°22]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E23 | Cahier n°23]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
| [[Atelier SysRes SE5 2023/2024 E24 | Cahier n°24]]&lt;br /&gt;
| || || || || || Prénom Nom&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Contrôle continu ==&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1188</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1188"/>
		<updated>2023-09-06T03:21:41Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 3 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconstituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconstituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconstituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconstituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 // Fonction pour copier un fichier existant du système de fichier&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[CHUNK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     int newDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconstituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                 // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
                 readBlock(numDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 if (chunkStart == 0) {&lt;br /&gt;
                     // Trouver un nouveau bloc de données disponible&lt;br /&gt;
                     newDataBlock = findAvailableBlock();&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la carte de disponibilités&lt;br /&gt;
                     setBlockAvailability(newDataBlock, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
                     createNumberBuffer(newDataBlock,numBuffer);&lt;br /&gt;
                     writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
                 }&lt;br /&gt;
             &lt;br /&gt;
                 // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
                 writeBlock(newDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans le fonction ci-dessus il n'y a plus de bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;, on a maintenant des blocs de 64 octets (&amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;). J'ai également créé la fonction &amp;lt;code&amp;gt;createNumberBuffer&amp;lt;/code&amp;gt; qui est la fonction inverse de&amp;lt;code&amp;gt;reconstituteNumber&amp;lt;/code&amp;gt;. Je la détaille ci-dessous.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
=== Fonction createNumberBuffer ===&lt;br /&gt;
Cette fonction permet repartir un entier sur deux octets.&lt;br /&gt;
 // Fonction qui réparti un numéro de bloc sur deux octets&lt;br /&gt;
 void createNumberBuffer(int dataBlockNum, unsigned char blockNumberBuffer[2]) {                    &lt;br /&gt;
     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
Voici ma version 3 de la fonction TYPE. Voici son fonctionnement:&lt;br /&gt;
&lt;br /&gt;
* tout d'abord, la fonction parcourt les blocs de description à la recherche d'un emplacement vide ;&lt;br /&gt;
* une fois l'emplacement vide trouvé, elle écrit le nom du fichier dans cet emplacement ;&lt;br /&gt;
* ensuite, on passe à la lecture de l'entrée standard. J'ai essayé d'expliquer au fur et à mesure du programme ce que font les lignes importantes via les commentaires. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     int index_description_block = 0; // indice du bloc de descrption&lt;br /&gt;
     int block_counter = 0; //compteur de blocs utilisés&lt;br /&gt;
     int index_in_descrBlock = 0;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int first_loop=1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 createNumberBuffer(dataBlockNum,blockNumberBuffer);&lt;br /&gt;
             &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant OU si c'est le premier tour dans la boucle&lt;br /&gt;
                 if (blockSizeUsed &amp;gt;= BLOCK_SIZE  || first_loop == 1) {&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la disponibilité du bloc&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     first_loop = 0;&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc utilisé dans les blocs de description&lt;br /&gt;
                     if (index_description_block == 0) {&lt;br /&gt;
                         offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
                     } else {&lt;br /&gt;
                         offset = 0;&lt;br /&gt;
                     }&lt;br /&gt;
                     // Ecriture du numéro de bloc dans le bloc de description&lt;br /&gt;
                     writeBlock(placeFound + index_description_block, offset + index_in_descrBlock*2, blockNumberBuffer, 2);&lt;br /&gt;
                     index_in_descrBlock++;&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     &lt;br /&gt;
                     // Passage au bloc de description suivant&lt;br /&gt;
                     if (block_counter == (BLOCK_SIZE/2-offset)) {&lt;br /&gt;
                         index_description_block++;&lt;br /&gt;
                         index_in_descrBlock=0;&lt;br /&gt;
                     }&lt;br /&gt;
                         &lt;br /&gt;
                     // Compteur de nombre de blocs utilisés&lt;br /&gt;
                     block_counter++;&lt;br /&gt;
                     &lt;br /&gt;
                     // Vérifie si on a atteint le nombre maximal de blocs par fichier&lt;br /&gt;
                     if (block_counter &amp;gt;= MAX_BLOCKS_PER_FILE) {&lt;br /&gt;
                         printf(&amp;quot;Le fichier a atteint sa taille maximale\n&amp;quot;);&lt;br /&gt;
                         return;&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; n'est pas placée au bon endroit, elle est parfois appelée inutilement.&lt;br /&gt;
&lt;br /&gt;
Amine: Effectivement, on peut ne l'appeler que lorsqu'un bloc a été complètement rempli donc après la condition&lt;br /&gt;
&lt;br /&gt;
ReX : La variable &amp;lt;code&amp;gt;blockSizeUsed&amp;lt;/code&amp;gt; peut dépasser &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; et cela donnera n'importe quoi.&lt;br /&gt;
&lt;br /&gt;
Amine: C'est vrai, je vais donc remplacer la condition if &amp;lt;code&amp;gt;(blockSizeUsed == BLOCK_SIZE  || first_loop == 1)&amp;lt;/code&amp;gt;  en &amp;lt;code&amp;gt;if (blockSizeUsed &amp;gt;= BLOCK_SIZE  || first_loop == 1)&amp;lt;/code&amp;gt;afin que la variable ne puisse pas dépasser &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
ReX : Si tu écris ton premier &amp;quot;chunk&amp;quot; de données tu ne remplis pas le bloc de données et tu en réclames un suivant.&lt;br /&gt;
&lt;br /&gt;
Amine: correction pas encore apportée&lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi &amp;lt;code&amp;gt;block_counter&amp;lt;/code&amp;gt; est initialisé à 1 ?&lt;br /&gt;
&lt;br /&gt;
Amine: Autant pour moi, il faut initialiser &amp;lt;code&amp;gt;block_counter&amp;lt;/code&amp;gt; à 0. Je l'avais initialisé à 1 car initialement dans mon programme nous n'entrions dans la condition que si un bloc était plein, mais j'ai ensuite modifié la condition en oubliant de modifier l'initialisation de la variable. &lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:PicofsV2.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1187</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1187"/>
		<updated>2023-09-06T03:15:55Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 3 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconstituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconstituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconstituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconstituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 // Fonction pour copier un fichier existant du système de fichier&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[CHUNK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     int newDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconstituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                 // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
                 readBlock(numDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 if (chunkStart == 0) {&lt;br /&gt;
                     // Trouver un nouveau bloc de données disponible&lt;br /&gt;
                     newDataBlock = findAvailableBlock();&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la carte de disponibilités&lt;br /&gt;
                     setBlockAvailability(newDataBlock, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
                     createNumberBuffer(newDataBlock,numBuffer);&lt;br /&gt;
                     writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
                 }&lt;br /&gt;
             &lt;br /&gt;
                 // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
                 writeBlock(newDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans le fonction ci-dessus il n'y a plus de bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;, on a maintenant des blocs de 64 octets (&amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;). J'ai également créé la fonction &amp;lt;code&amp;gt;createNumberBuffer&amp;lt;/code&amp;gt; qui est la fonction inverse de&amp;lt;code&amp;gt;reconstituteNumber&amp;lt;/code&amp;gt;. Je la détaille ci-dessous.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
=== Fonction createNumberBuffer ===&lt;br /&gt;
Cette fonction permet repartir un entier sur deux octets.&lt;br /&gt;
 // Fonction qui réparti un numéro de bloc sur deux octets&lt;br /&gt;
 void createNumberBuffer(int dataBlockNum, unsigned char blockNumberBuffer[2]) {                    &lt;br /&gt;
     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
Voici ma version 3 de la fonction TYPE. Voici son fonctionnement:&lt;br /&gt;
&lt;br /&gt;
* tout d'abord, la fonction parcourt les blocs de description à la recherche d'un emplacement vide ;&lt;br /&gt;
* une fois l'emplacement vide trouvé, elle écrit le nom du fichier dans cet emplacement ;&lt;br /&gt;
* ensuite, on passe à la lecture de l'entrée standard. J'ai essayé d'expliquer au fur et à mesure du programme ce que font les lignes importantes via les commentaires. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     int index_description_block = 0; // indice du bloc de descrption&lt;br /&gt;
     int block_counter = 1; //compteur de blocs utilisés&lt;br /&gt;
     int index_in_descrBlock = 0;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int first_loop=1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 createNumberBuffer(dataBlockNum,blockNumberBuffer);&lt;br /&gt;
             &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant OU si c'est le premier tour dans la boucle&lt;br /&gt;
                 if (blockSizeUsed &amp;gt;= BLOCK_SIZE  || first_loop == 1) {&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la disponibilité du bloc&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     first_loop = 0;&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc utilisé dans les blocs de description&lt;br /&gt;
                     if (index_description_block == 0) {&lt;br /&gt;
                         offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
                     } else {&lt;br /&gt;
                         offset = 0;&lt;br /&gt;
                     }&lt;br /&gt;
                     // Ecriture du numéro de bloc dans le bloc de description&lt;br /&gt;
                     writeBlock(placeFound + index_description_block, offset + index_in_descrBlock*2, blockNumberBuffer, 2);&lt;br /&gt;
                     index_in_descrBlock++;&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     &lt;br /&gt;
                     // Passage au bloc de description suivant&lt;br /&gt;
                     if (block_counter == (BLOCK_SIZE/2-offset)) {&lt;br /&gt;
                         index_description_block++;&lt;br /&gt;
                         index_in_descrBlock=0;&lt;br /&gt;
                     }&lt;br /&gt;
                         &lt;br /&gt;
                     // Compteur de nombre de blocs utilisés&lt;br /&gt;
                     block_counter++;&lt;br /&gt;
                     &lt;br /&gt;
                     // Vérifie si on a atteint le nombre maximal de blocs par fichier&lt;br /&gt;
                     if (block_counter &amp;gt;= MAX_BLOCKS_PER_FILE) {&lt;br /&gt;
                         printf(&amp;quot;Le fichier a atteint sa taille maximale\n&amp;quot;);&lt;br /&gt;
                         return;&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; n'est pas placée au bon endroit, elle est parfois appelée inutilement.&lt;br /&gt;
&lt;br /&gt;
Amine: Effectivement, on peut ne l'appeler que lorsqu'un bloc a été complètement rempli donc après la condition&lt;br /&gt;
&lt;br /&gt;
ReX : La variable &amp;lt;code&amp;gt;blockSizeUsed&amp;lt;/code&amp;gt; peut dépasser &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; et cela donnera n'importe quoi.&lt;br /&gt;
&lt;br /&gt;
Amine: C'est vrai, je vais donc remplacer la condition if &amp;lt;code&amp;gt;(blockSizeUsed == BLOCK_SIZE  || first_loop == 1)&amp;lt;/code&amp;gt;  en &amp;lt;code&amp;gt;if (blockSizeUsed &amp;gt;= BLOCK_SIZE  || first_loop == 1)&amp;lt;/code&amp;gt;afin que la variable ne puisse pas dépasser &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
ReX : Si tu écris ton premier &amp;quot;chunk&amp;quot; de données tu ne remplis pas le bloc de données et tu en réclames un suivant.&lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi &amp;lt;code&amp;gt;block_counter&amp;lt;/code&amp;gt; est initialisé à 1 ?&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:PicofsV2.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1056</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1056"/>
		<updated>2023-09-04T18:36:53Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 3 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 // Fonction pour copier un fichier existant du système de fichier&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[CHUNK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     int newDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                 // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
                 readBlock(numDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 if (chunkStart == 0) {&lt;br /&gt;
                     // Trouver un nouveau bloc de données disponible&lt;br /&gt;
                     newDataBlock = findAvailableBlock();&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la carte de disponibilités&lt;br /&gt;
                     setBlockAvailability(newDataBlock, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
                     createNumberBuffer(newDataBlock,numBuffer);&lt;br /&gt;
                     writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
                 }&lt;br /&gt;
             &lt;br /&gt;
                 // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
                 writeBlock(newDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans le fonction ci-dessus il n'y a plus de bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;, on a maintenant des blocs de 64 octets (&amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;). J'ai également créé la fonction &amp;lt;code&amp;gt;createNumberBuffer&amp;lt;/code&amp;gt; qui est la fonction inverse de&amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;. Je la détaille ci-dessous.&lt;br /&gt;
&lt;br /&gt;
=== Fonction createNumberBuffer ===&lt;br /&gt;
Cette fonction permet repartir un entier sur deux octets.&lt;br /&gt;
 // Fonction qui réparti un numéro de bloc sur deux octets&lt;br /&gt;
 void createNumberBuffer(int dataBlockNum, unsigned char blockNumberBuffer[2]) {                    &lt;br /&gt;
     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
Voici ma version 3 de la fonction TYPE. Voici son fonctionnement:&lt;br /&gt;
&lt;br /&gt;
- tout d'abord, la fonction parcours les blocs de description à la recherche d'un emplacement vide&lt;br /&gt;
&lt;br /&gt;
- une fois l'emplacement vide trouvé, elle écrit le nom du fichier dans cet emplacement&lt;br /&gt;
&lt;br /&gt;
- ensuite, on passe à la lecture de l'entrée standard. J'ai essayé d'expliquer au fur et à mesure du programme ce que font les lignes importantes via les commentaires. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     int index_description_block = 0; // indice du bloc de descrption&lt;br /&gt;
     int block_counter = 1; //compteur de blocs utilisés&lt;br /&gt;
     int index_in_descrBlock = 0;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int first_loop=1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 createNumberBuffer(dataBlockNum,blockNumberBuffer);&lt;br /&gt;
             &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant OU si c'est le premier tour dans la boucle&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE  || first_loop == 1) {&lt;br /&gt;
                     &lt;br /&gt;
                     first_loop = -1;&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc utilisé dans les blocs de description&lt;br /&gt;
                     if (index_description_block == 0) {&lt;br /&gt;
                         offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
                     } else {&lt;br /&gt;
                         offset = 0;&lt;br /&gt;
                     }&lt;br /&gt;
                     writeBlock(placeFound + index_description_block, offset + index_in_descrBlock*2, blockNumberBuffer, 2);&lt;br /&gt;
                     index_in_descrBlock++;&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     &lt;br /&gt;
                     // Passage au bloc de description suivant&lt;br /&gt;
                     if (block_counter == (BLOCK_SIZE/2-offset)) {&lt;br /&gt;
                         index_description_block++;&lt;br /&gt;
                         index_in_descrBlock=0;&lt;br /&gt;
                     }&lt;br /&gt;
                         &lt;br /&gt;
                     // Compteur de nombre de blocs utilisés&lt;br /&gt;
                     block_counter++;&lt;br /&gt;
                     &lt;br /&gt;
                     // Vérifie si on a atteint le nombre maximal de blocs par fichier&lt;br /&gt;
                     if (block_counter &amp;gt;= MAX_BLOCKS_PER_FILE) {&lt;br /&gt;
                         printf(&amp;quot;Le fichier a atteint sa taille maximale\n&amp;quot;);&lt;br /&gt;
                         return;&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:PicofsV2.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1055</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1055"/>
		<updated>2023-09-04T18:33:29Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Documents Rendus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 // Fonction pour copier un fichier existant du système de fichier&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[CHUNK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     int newDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                 // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
                 readBlock(numDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 if (chunkStart == 0) {&lt;br /&gt;
                     // Trouver un nouveau bloc de données disponible&lt;br /&gt;
                     newDataBlock = findAvailableBlock();&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la carte de disponibilités&lt;br /&gt;
                     setBlockAvailability(newDataBlock, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
                     createNumberBuffer(newDataBlock,numBuffer);&lt;br /&gt;
                     writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
                 }&lt;br /&gt;
             &lt;br /&gt;
                 // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
                 writeBlock(newDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans le fonction ci-dessus il n'y a plus de bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;, on a maintenant des blocs de 64 octets (&amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;). J'ai également créé la fonction &amp;lt;code&amp;gt;createNumberBuffer&amp;lt;/code&amp;gt; qui est la fonction inverse de&amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;. Je la détaille ci-dessous.&lt;br /&gt;
&lt;br /&gt;
=== Fonction createNumberBuffer ===&lt;br /&gt;
Cette fonction permet repartir un entier sur deux octets.&lt;br /&gt;
 // Fonction qui réparti un numéro de bloc sur deux octets&lt;br /&gt;
 void createNumberBuffer(int dataBlockNum, unsigned char blockNumberBuffer[2]) {                    &lt;br /&gt;
     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
Voici ma version 3 de la fonction TYPE. Voici son fonctionnement:&lt;br /&gt;
&lt;br /&gt;
- tout d'abord, la fonction parcours les blocs de description à la recherche d'un emplacement vide&lt;br /&gt;
&lt;br /&gt;
- une fois l'emplacement vide trouvé, elle écrit le nom du fichier dans cet emplacement&lt;br /&gt;
&lt;br /&gt;
- ensuite, on passe à la lecture de l'entrée standard. J'ai essayé d'expliquer au fur et à mesure du programme ce que font les lignes importantes via les commentaires. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     int index_description_block = 0; // indice du bloc de descrption&lt;br /&gt;
     int block_counter = 1; //compteur de blocs utilisés&lt;br /&gt;
     int index_in_descrBlock = 0;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int first_loop=1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 createNumberBuffer(dataBlockNum,blockNumberBuffer);&lt;br /&gt;
             &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant OU si c'est le premier tour dans la boucle&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE  || first_loop == 1) {&lt;br /&gt;
                     &lt;br /&gt;
                     first_loop = -1;&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc utilisé dans les blocs de description&lt;br /&gt;
                     if (index_description_block == 0) {&lt;br /&gt;
                         offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
                     } else {&lt;br /&gt;
                         offset = 0;&lt;br /&gt;
                     }&lt;br /&gt;
                     writeBlock(placeFound + index_description_block, offset + index_in_descrBlock*2, blockNumberBuffer, 2);&lt;br /&gt;
                     index_in_descrBlock++;&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     &lt;br /&gt;
                     // Passage au bloc de description suivant&lt;br /&gt;
                     if (block_counter == (BLOCK_SIZE/2-offset)) {&lt;br /&gt;
                         index_description_block++;&lt;br /&gt;
                         index_in_descrBlock=0;&lt;br /&gt;
                     }&lt;br /&gt;
                         &lt;br /&gt;
                     // Compteur de nombre de blocs utilisés&lt;br /&gt;
                     block_counter++;&lt;br /&gt;
                     &lt;br /&gt;
                     // Vérifie si on a atteint le nombre maximal de blocs par fichier&lt;br /&gt;
                     if (block_counter &amp;gt;= 2040) {&lt;br /&gt;
                         printf(&amp;quot;Le fichier a atteint sa taille maximale\n&amp;quot;);&lt;br /&gt;
                         return;&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:PicofsV2.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:PicofsV2.c.tar&amp;diff=1054</id>
		<title>Fichier:PicofsV2.c.tar</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:PicofsV2.c.tar&amp;diff=1054"/>
		<updated>2023-09-04T18:33:22Z</updated>

		<summary type="html">&lt;p&gt;Asellali : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;picofs&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1053</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1053"/>
		<updated>2023-09-04T18:32:07Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 3 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 // Fonction pour copier un fichier existant du système de fichier&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[CHUNK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     int newDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                 // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
                 readBlock(numDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 if (chunkStart == 0) {&lt;br /&gt;
                     // Trouver un nouveau bloc de données disponible&lt;br /&gt;
                     newDataBlock = findAvailableBlock();&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la carte de disponibilités&lt;br /&gt;
                     setBlockAvailability(newDataBlock, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
                     createNumberBuffer(newDataBlock,numBuffer);&lt;br /&gt;
                     writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
                 }&lt;br /&gt;
             &lt;br /&gt;
                 // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
                 writeBlock(newDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans le fonction ci-dessus il n'y a plus de bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;, on a maintenant des blocs de 64 octets (&amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;). J'ai également créé la fonction &amp;lt;code&amp;gt;createNumberBuffer&amp;lt;/code&amp;gt; qui est la fonction inverse de&amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;. Je la détaille ci-dessous.&lt;br /&gt;
&lt;br /&gt;
=== Fonction createNumberBuffer ===&lt;br /&gt;
Cette fonction permet repartir un entier sur deux octets.&lt;br /&gt;
 // Fonction qui réparti un numéro de bloc sur deux octets&lt;br /&gt;
 void createNumberBuffer(int dataBlockNum, unsigned char blockNumberBuffer[2]) {                    &lt;br /&gt;
     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
Voici ma version 3 de la fonction TYPE. Voici son fonctionnement:&lt;br /&gt;
&lt;br /&gt;
- tout d'abord, la fonction parcours les blocs de description à la recherche d'un emplacement vide&lt;br /&gt;
&lt;br /&gt;
- une fois l'emplacement vide trouvé, elle écrit le nom du fichier dans cet emplacement&lt;br /&gt;
&lt;br /&gt;
- ensuite, on passe à la lecture de l'entrée standard. J'ai essayé d'expliquer au fur et à mesure du programme ce que font les lignes importantes via les commentaires. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     int index_description_block = 0; // indice du bloc de descrption&lt;br /&gt;
     int block_counter = 1; //compteur de blocs utilisés&lt;br /&gt;
     int index_in_descrBlock = 0;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int first_loop=1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 createNumberBuffer(dataBlockNum,blockNumberBuffer);&lt;br /&gt;
             &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant OU si c'est le premier tour dans la boucle&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE  || first_loop == 1) {&lt;br /&gt;
                     &lt;br /&gt;
                     first_loop = -1;&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc utilisé dans les blocs de description&lt;br /&gt;
                     if (index_description_block == 0) {&lt;br /&gt;
                         offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
                     } else {&lt;br /&gt;
                         offset = 0;&lt;br /&gt;
                     }&lt;br /&gt;
                     writeBlock(placeFound + index_description_block, offset + index_in_descrBlock*2, blockNumberBuffer, 2);&lt;br /&gt;
                     index_in_descrBlock++;&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     &lt;br /&gt;
                     // Passage au bloc de description suivant&lt;br /&gt;
                     if (block_counter == (BLOCK_SIZE/2-offset)) {&lt;br /&gt;
                         index_description_block++;&lt;br /&gt;
                         index_in_descrBlock=0;&lt;br /&gt;
                     }&lt;br /&gt;
                         &lt;br /&gt;
                     // Compteur de nombre de blocs utilisés&lt;br /&gt;
                     block_counter++;&lt;br /&gt;
                     &lt;br /&gt;
                     // Vérifie si on a atteint le nombre maximal de blocs par fichier&lt;br /&gt;
                     if (block_counter &amp;gt;= 2040) {&lt;br /&gt;
                         printf(&amp;quot;Le fichier a atteint sa taille maximale\n&amp;quot;);&lt;br /&gt;
                         return;&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:PicofsV1.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1013</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1013"/>
		<updated>2023-09-03T21:06:39Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Documents Rendus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 // Fonction pour copier un fichier existant du système de fichier&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[CHUNK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     int newDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                 // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
                 readBlock(numDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 if (chunkStart == 0) {&lt;br /&gt;
                     // Trouver un nouveau bloc de données disponible&lt;br /&gt;
                     newDataBlock = findAvailableBlock();&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la carte de disponibilités&lt;br /&gt;
                     setBlockAvailability(newDataBlock, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
                     createNumberBuffer(newDataBlock,numBuffer);&lt;br /&gt;
                     writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
                 }&lt;br /&gt;
             &lt;br /&gt;
                 // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
                 writeBlock(newDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans le fonction ci-dessus il n'y a plus de bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;, on a maintenant des blocs de 64 octets (&amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;). J'ai également créé la fonction &amp;lt;code&amp;gt;createNumberBuffer&amp;lt;/code&amp;gt; qui est la fonction inverse de&amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;. Je la détaille ci-dessous.&lt;br /&gt;
&lt;br /&gt;
=== Fonction createNumberBuffer ===&lt;br /&gt;
Cette fonction permet repartir un entier sur deux octets.&lt;br /&gt;
 // Fonction qui réparti un numéro de bloc sur deux octets&lt;br /&gt;
 void createNumberBuffer(int dataBlockNum, unsigned char blockNumberBuffer[2]) {                    &lt;br /&gt;
     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:PicofsV1.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:PicofsV1.c.tar&amp;diff=1012</id>
		<title>Fichier:PicofsV1.c.tar</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:PicofsV1.c.tar&amp;diff=1012"/>
		<updated>2023-09-03T21:06:31Z</updated>

		<summary type="html">&lt;p&gt;Asellali : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;picofs&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1007</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1007"/>
		<updated>2023-09-03T19:31:21Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 // Fonction pour copier un fichier existant du système de fichier&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[CHUNK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     int newDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                 // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
                 readBlock(numDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 if (chunkStart == 0) {&lt;br /&gt;
                     // Trouver un nouveau bloc de données disponible&lt;br /&gt;
                     newDataBlock = findAvailableBlock();&lt;br /&gt;
                     &lt;br /&gt;
                     // Mise à jour de la carte de disponibilités&lt;br /&gt;
                     setBlockAvailability(newDataBlock, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
                     createNumberBuffer(newDataBlock,numBuffer);&lt;br /&gt;
                     writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
                 }&lt;br /&gt;
             &lt;br /&gt;
                 // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
                 writeBlock(newDataBlock, chunkStart, descriptionBuffer, CHUNK_SIZE);&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Voilà! Dans le fonction ci-dessus il n'y a plus de bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt;, on a maintenant des blocs de 64 octets (&amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;). J'ai également créé la fonction &amp;lt;code&amp;gt;createNumberBuffer&amp;lt;/code&amp;gt; qui est la fonction inverse de&amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;. Je la détaille ci-dessous.&lt;br /&gt;
&lt;br /&gt;
=== Fonction createNumberBuffer ===&lt;br /&gt;
Cette fonction permet repartir un entier sur deux octets.&lt;br /&gt;
 // Fonction qui réparti un numéro de bloc sur deux octets&lt;br /&gt;
 void createNumberBuffer(int dataBlockNum, unsigned char blockNumberBuffer[2]) {                    &lt;br /&gt;
     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystemv2.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1006</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=1006"/>
		<updated>2023-09-03T18:32:55Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CAT version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : OK, bien vu.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ci-dessus.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans le cadre de la fonction CAT le &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; est convenable.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointer les blocs de données du fichier destination vers ceux du fichier source, toute modification du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pas mieux.&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
&lt;br /&gt;
ReX : Un seul plus petit.&lt;br /&gt;
&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
ReX : Déjà validé. &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[CHUNK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                     &lt;br /&gt;
                     for (int chunkStart = 0; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
                         // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                         readBlock(dataBlockNum, chunkStart, dataBuffer, CHUNK_SIZE);&lt;br /&gt;
                         fwrite(dataBuffer, 1, CHUNK_SIZE, stdout);&lt;br /&gt;
                     }&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Remplacer le premier bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets par un bloc de 2 octets est exagéré mais cela pourrait passer. Il reste toujours un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets dont il est facile de se passer au bénéfice d'un bloc de, mettons, 64 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: voilà, dans la version ci-dessus j'ai remplacé le bloc de taille &amp;lt;code&amp;gt;BLOC_SIZE&amp;lt;/code&amp;gt; par un bloc de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;, avec &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; modifiable dans les constantes du programme. J'ai pris ici 64 octets.&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Bonne idée cette fonction.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
             readBlock(numDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
                   &lt;br /&gt;
             // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
             writeBlock(newDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Mise à jour de la carte de disponibilités&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
             numBuffer[0] = (newDataBlock &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
             numBuffer[1] = newDataBlock &amp;amp; 0xFF;&lt;br /&gt;
             writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Youpi. Il reste à se passer du bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; (au bénéfice d'un bloc de taille &amp;lt;code&amp;gt;BLOCK_SIZE/n&amp;lt;/code&amp;gt; avec n&amp;gt;1). Ecrire la fonction inverse de &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corriger dans cette version 3.&lt;br /&gt;
&lt;br /&gt;
ReX : Effectivement la version précédente ne gére pas correctement l'écriture des numéros de blocs de données dans la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystemv2.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=984</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=984"/>
		<updated>2023-09-02T16:22:11Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Documents Rendus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un return &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                     readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
             readBlock(numDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
                   &lt;br /&gt;
             // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
             writeBlock(newDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Mise à jour de la carte de disponibilités&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
             numBuffer[0] = (newDataBlock &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
             numBuffer[1] = newDataBlock &amp;amp; 0xFF;&lt;br /&gt;
             writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corrigé dans cette version 3&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystemv2.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Picofilesystemv2.c.tar&amp;diff=983</id>
		<title>Fichier:Picofilesystemv2.c.tar</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Picofilesystemv2.c.tar&amp;diff=983"/>
		<updated>2023-09-02T16:21:59Z</updated>

		<summary type="html">&lt;p&gt;Asellali : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;pico file system&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=982</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=982"/>
		<updated>2023-09-02T16:20:35Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un return &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                     readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
             readBlock(numDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
                   &lt;br /&gt;
             // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
             writeBlock(newDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Mise à jour de la carte de disponibilités&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
             numBuffer[0] = (newDataBlock &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
             numBuffer[1] = newDataBlock &amp;amp; 0xFF;&lt;br /&gt;
             writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 3 ===&lt;br /&gt;
La fonction 2 que j'ai fourni ci-dessus n'est pas correcte. Je vais la corrigé dans cette version 3&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=981</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=981"/>
		<updated>2023-09-02T16:19:34Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un return &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                     readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP. Dans la version précédente, on faisait pointer le fichier source vers les même blocs que le fichier destination. Cela posait un problème: toute modification du fichier source impactait le fichier destination. Ainsi, dans cette nouvelle version, on fait une duplication des blocs de données du fichier source vers le fichier destination. Cela implique donc une mise à jour de la carte de disponibilité, ainsi que l'adaptation des blocs de descriptions. En effet, seulement les blocs de données sont maintenant identiques, plus les blocs de description. &lt;br /&gt;
&lt;br /&gt;
Piste d'amélioration: comme pour la fonction CAT ci-dessus, j'utilise toujours un bloc de taille 256 octets, je vais devoir y remédier. &lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char numBuffer[2];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     int numDataBlock;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) { offset = MAX_FILENAME_LENGTH; } &lt;br /&gt;
         else { offset = 0; }&lt;br /&gt;
         &lt;br /&gt;
         // Lecture des numéros de bloc dans les blocs de description&lt;br /&gt;
         for (int byteNum=0; byteNum&amp;lt;BLOCK_SIZE; byteNum+=2) {&lt;br /&gt;
             readBlock(source_offset + i, offset + byteNum, numBuffer, 2);&lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             numDataBlock = reconsituteNumber(numBuffer);&lt;br /&gt;
             if (numDataBlock == 0) {&lt;br /&gt;
                 return;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // On stocke le bloc de données associé au fichier source dans descriptionBuffer&lt;br /&gt;
             readBlock(numDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
                   &lt;br /&gt;
             // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du bloc de données dans le premier bloc disponible&lt;br /&gt;
             writeBlock(newDataBlock, 0, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Mise à jour de la carte de disponibilités&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); &lt;br /&gt;
             &lt;br /&gt;
             // Ecriture du numéro de bloc dans la description du fichier&lt;br /&gt;
             numBuffer[0] = (newDataBlock &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
             numBuffer[1] = newDataBlock &amp;amp; 0xFF;&lt;br /&gt;
             writeBlock(destination_offset+i, offset+byteNum, numBuffer, 2);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=978</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=978"/>
		<updated>2023-09-02T11:38:39Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un return &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                     readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP qui duplique réellement les blocs de données du fichier source vers le fichier de destination. Cela implique d'attribuer de nouveaux blocs de données au fichier de destination et de mettre à jour la carte de disponibilité des blocs.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) {&lt;br /&gt;
             int offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         } else {&lt;br /&gt;
             int offset = 0;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=977</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=977"/>
		<updated>2023-09-02T11:37:31Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Semaine 8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP qui duplique réellement les blocs de données du fichier source vers le fichier de destination. Cela implique d'attribuer de nouveaux blocs de données au fichier de destination et de mettre à jour la carte de disponibilité des blocs.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) {&lt;br /&gt;
             int offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         } else {&lt;br /&gt;
             int offset = 0;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un return &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                     readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=976</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=976"/>
		<updated>2023-09-02T11:36:27Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CAT version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 1 ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP qui duplique réellement les blocs de données du fichier source vers le fichier de destination. Cela implique d'attribuer de nouveaux blocs de données au fichier de destination et de mettre à jour la carte de disponibilité des blocs.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) {&lt;br /&gt;
             int offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         } else {&lt;br /&gt;
             int offset = 0;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Semaine 8 ==&lt;br /&gt;
A ce stade du projet, les fonctions suivantes ont été validé par Monsieur Redon:&lt;br /&gt;
&lt;br /&gt;
* fonction LS&lt;br /&gt;
* fonction RM&lt;br /&gt;
* fonction MV&lt;br /&gt;
&lt;br /&gt;
Il reste donc les fonctions suivantes à terminer:&lt;br /&gt;
&lt;br /&gt;
* fonction TYPE&lt;br /&gt;
* fonction CAT&lt;br /&gt;
* fonction CP&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT version 2 ===&lt;br /&gt;
Suite à vos remarques sur la version 1, j'ai fais les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'utilise non plus 2 tableaux de taille BLOCK_SIZE, mais 1 seul. Idéalement il faudrait en utiliser 0, je réfléchi donc à m’émanciper de ce tableau en le remplaçant par plusieurs plus petits tableaux.&lt;br /&gt;
* J'ai remplacé le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; par un return &lt;br /&gt;
&lt;br /&gt;
Cette fonction permet d'afficher le contenu d'un fichier créé avec la fonction TYPE. Pour se faire, on parcours tout d'abord les blocs de descriptions pour trouver le fichier dont ont veut afficher le contenu. Une fois ce fichier trouvé, on parcours les 16 blocs de description de ce fichier 1 à 1. Pour chacun de ces blocs de description, on va stocker récupéré les octets deux par deux afin de former des entiers. Pour se faire, on utilise la fonction &amp;lt;code&amp;gt;reconsituteNumber&amp;lt;/code&amp;gt; que l'on détaillera juste après. Ces entiers correspondent aux blocs dans lesquels la donné du fichier se trouve. Une fois l'entier reconstitué, on affiche le contenu du bloc correspondant.&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char byteBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=MAX_FILENAME_LENGTH;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lecture des octets deux par deux&lt;br /&gt;
                 for (int i=0; i&amp;lt;BLOCK_SIZE;i+=2) {&lt;br /&gt;
                     readBlock(descrBlockNum+blockNum, offset+i, byteBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                     int dataBlockNum = reconsituteNumber(byteBuffer);&lt;br /&gt;
                 &lt;br /&gt;
                     // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                     if (dataBlockNum == 0) {&lt;br /&gt;
                         return; // Fin du fichier&lt;br /&gt;
                     }&lt;br /&gt;
                 &lt;br /&gt;
                     // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                     readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction reconsituteNumber ===&lt;br /&gt;
Cette fonction permet de reconstituer un numéro de bloc à partir de deux octets.&lt;br /&gt;
 // Fonction qui reconstitue le numéro de bloc à partir du tableau&lt;br /&gt;
 int reconsituteNumber(unsigned char blockNumberBuffer[2]) {&lt;br /&gt;
     unsigned char octet1 = blockNumberBuffer[0];&lt;br /&gt;
     unsigned char octet2 = blockNumberBuffer[1];&lt;br /&gt;
     int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
     return dataBlockNum;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=963</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=963"/>
		<updated>2023-08-28T14:32:24Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction findAvailableBlock */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE - offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP qui duplique réellement les blocs de données du fichier source vers le fichier de destination. Cela implique d'attribuer de nouveaux blocs de données au fichier de destination et de mettre à jour la carte de disponibilité des blocs.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) {&lt;br /&gt;
             int offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         } else {&lt;br /&gt;
             int offset = 0;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=962</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=962"/>
		<updated>2023-08-28T14:02:44Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui autant pour moi.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
* je n'utilise plus de tableaux de taille 256 octets mais des tableaux de tailles CHUNK_SIZE. J'ai choisi ici CHUNK_SIZE = 64 octets.&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard et écrire dans le fichier&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;, dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             unsigned char chunkBuffer[CHUNK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(chunkBuffer, 1, CHUNK_SIZE, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le chunk dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, blockSizeUsed, chunkBuffer, bytesRead);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 &lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP qui duplique réellement les blocs de données du fichier source vers le fichier de destination. Cela implique d'attribuer de nouveaux blocs de données au fichier de destination et de mettre à jour la carte de disponibilité des blocs.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) {&lt;br /&gt;
             int offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         } else {&lt;br /&gt;
             int offset = 0;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=956</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=956"/>
		<updated>2023-08-27T20:19:45Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Documents Rendus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // Écrire le bloc actuel dans le bloc de données&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                     unsigned char blockNumberBuffer[2];&lt;br /&gt;
                     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                     writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le bloc partiel dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc partiel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP qui duplique réellement les blocs de données du fichier source vers le fichier de destination. Cela implique d'attribuer de nouveaux blocs de données au fichier de destination et de mettre à jour la carte de disponibilité des blocs.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) {&lt;br /&gt;
             int offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         } else {&lt;br /&gt;
             int offset = 0;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Pcfs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Pcfs.c.tar&amp;diff=955</id>
		<title>Fichier:Pcfs.c.tar</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Pcfs.c.tar&amp;diff=955"/>
		<updated>2023-08-27T20:19:37Z</updated>

		<summary type="html">&lt;p&gt;Asellali : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;picofs&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=954</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=954"/>
		<updated>2023-08-27T20:14:02Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // Écrire le bloc actuel dans le bloc de données&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                     unsigned char blockNumberBuffer[2];&lt;br /&gt;
                     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                     writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le bloc partiel dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc partiel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir fait des recherches et après réflexion, je me rends compte que cette fonction CP présente un problème: en faisant pointé les blocs de données du fichier destination vers ceux du fichier source, toutes modifications du fichier source impactera le fichier destination, or ce n'est pas ce qu'on veut faire. Je vous propose donc une nouvelle version de la fonction CP ci-dessous qui remédie à ce problème.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 2 ===&lt;br /&gt;
Voici une version mise à jour de notre fonction CP qui duplique réellement les blocs de données du fichier source vers le fichier de destination. Cela implique d'attribuer de nouveaux blocs de données au fichier de destination et de mettre à jour la carte de disponibilité des blocs.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int source_offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Copie du nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de données associés au fichier source dans de nouveaux blocs de données pour le fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i == 0) {&lt;br /&gt;
             int offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE - offset);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         } else {&lt;br /&gt;
             int offset = 0;&lt;br /&gt;
             readBlock(source_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             if (descriptionBuffer[offset] == 0) {&lt;br /&gt;
                 break;&lt;br /&gt;
             }&lt;br /&gt;
             int newDataBlock = findAvailableBlock(); // Trouver un nouveau bloc de données disponible&lt;br /&gt;
             writeBlock(destination_offset + i, offset, descriptionBuffer, BLOCK_SIZE);&lt;br /&gt;
             setBlockAvailability(newDataBlock, 1); // Marquer le nouveau bloc de données comme utilisé&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=951</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=951"/>
		<updated>2023-08-26T18:46:25Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CAT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // Écrire le bloc actuel dans le bloc de données&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                     unsigned char blockNumberBuffer[2];&lt;br /&gt;
                     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                     writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le bloc partiel dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc partiel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE-offset);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     return; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Amine: Oui c'est vrai. J'ai remplacé le break pas un return ci-dessus.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=950</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=950"/>
		<updated>2023-08-26T18:34:48Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // Écrire le bloc actuel dans le bloc de données&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                     unsigned char blockNumberBuffer[2];&lt;br /&gt;
                     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                     writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le bloc partiel dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc partiel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 afin de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=949</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=949"/>
		<updated>2023-08-26T16:12:05Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction findAvailableBlock */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // Écrire le bloc actuel dans le bloc de données&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                     unsigned char blockNumberBuffer[2];&lt;br /&gt;
                     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                     writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le bloc partiel dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc partiel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 #define FIRST_DATA_BLOCK 1040&lt;br /&gt;
 #define FIRST_DISPONIBILITY_CARD_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = FIRST_DISPONIBILITY_CARD_BLOCK; blockNum &amp;lt; FIRST_DATA_BLOCK; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==FIRST_DISPONIBILITY_CARD_BLOCK) {&lt;br /&gt;
             offset=FIRST_DATA_BLOCK/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK dans la fonction ci-dessus. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: dois-je découper le bloc de taille BLOCK_SIZE en quatre blocs de taille 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: dans la carte de disponibilité, chaque bit correspond à un bloc. Ainsi, les bits de 0 à 1040 dans la carte de disponibilité décrivent la disponibilité des blocs 0 à 1040. Or ces blocs correspondent au superbloc, et dans cette fonction, on veut connaître le premier bloc de données disponible. On ne s'intéresse donc pas au 1040 premiers bits de la carte de disponibilité. Je crée donc un offset égal à 1040/8 avant de ne pas prendre en compte les 1040 premiers bits soit les 1040/8=130 premiers octets. Cet offset ne s'applique que lorsqu'on se trouve dans le premier des 16 blocs de la carte de disponibilité, d'où la condition &amp;lt;code&amp;gt;if (blockNum==1024)&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=948</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=948"/>
		<updated>2023-08-26T15:34:36Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction findAvailableBlock */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = FIRST_DISPONIBILITY_CARD_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // Écrire le bloc actuel dans le bloc de données&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                     unsigned char blockNumberBuffer[2];&lt;br /&gt;
                     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                     writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le bloc partiel dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc partiel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, j'ai remplacé 1024 par la constante FIRST_DISPONIBILITY_CARD_BLOCK et 1040 par la constante FIRST_DATA_BLOCK. &lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=947</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=947"/>
		<updated>2023-08-26T15:21:17Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok. Je ne l'avais pas défini comme une constante car il s'agit dans la fonction ci-dessus d'une variable qui est incrémenté à chaque itération. &lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Amine: Comment utiliser des blocs plus petit sachant qu'il s'agit là de blocs de données et qu'un bloc fait 256 octets d'après l'énoncé ? Dois-je les subdiviser en plusieurs blocs plus petit comme fait dans la fonction RM, en 4 blocs de 64 octets par exemple ?&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je ferai cela dans la version 2&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
Amine: je corrige cela dans la version 2. J'ai bien compris le mécanisme mais ce n'est pas facile à traduire en code. &lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 2 ===&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai fait les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'appelle maintenant &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser&lt;br /&gt;
* j'écris maintenant les numéros de blocs au fur et à mesures des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
J'utilise toujours un bloc de taille BLOCK_SIZE en attendant de comprendre si je dois diviser ce bloc en plusieurs blocs de taille plus petite ou s'il y a un moyen de ne pas du tout utiliser ces blocs. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;Premier bloc dans lequel on écrit = %d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // Écrire le bloc actuel dans le bloc de données&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     // Écrire le numéro du bloc actuel dans la description du fichier&lt;br /&gt;
                     unsigned char blockNumberBuffer[2];&lt;br /&gt;
                     blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                     blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                     writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum = findAvailableBlock(); // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 // Écrire le bloc partiel dans le bloc de données&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                 &lt;br /&gt;
                 // Écrire le numéro du bloc partiel dans la description du fichier&lt;br /&gt;
                 unsigned char blockNumberBuffer[2];&lt;br /&gt;
                 blockNumberBuffer[0] = (dataBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = dataBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + dataBlockNum * 2, blockNumberBuffer, 2);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=936</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=936"/>
		<updated>2023-08-24T15:41:49Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP version 1 ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=935</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=935"/>
		<updated>2023-08-24T15:37:40Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction intermédiaire TYPE */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=934</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=934"/>
		<updated>2023-08-24T15:37:18Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction LS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 1 ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=933</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=933"/>
		<updated>2023-08-24T15:37:02Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction RM */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 1 ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=932</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=932"/>
		<updated>2023-08-24T15:36:41Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction setBlockAvailability */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 1 ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=931</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=931"/>
		<updated>2023-08-24T15:36:27Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction setBlockAvailability */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 3 ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=930</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=930"/>
		<updated>2023-08-24T15:36:04Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction LS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 2 ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=929</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=929"/>
		<updated>2023-08-24T15:35:47Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction LS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS ===&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS ===&lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== Fonction LS version 3 ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability ===&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability version 2 ===&lt;br /&gt;
&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== Fonction setBlockAvailability ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM ===&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 2 ===&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 3 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE ===&lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
=== Fonction intermédiaire TYPE version 2 ===&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 1 ===&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour ce faire, la fonction parcourt les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais faire les modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : C'est bon. La fonction était triviale.&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : La constante 1040 ne doit pas apparaître en numérique, ce doit être une constante calculée à partir des autres constantes.&lt;br /&gt;
&lt;br /&gt;
ReX : Je suis las de te répéter que le mémoire est comptée : tu utilises encore un bloc de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; octets, c'est trop.&lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcourt les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l'étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
&lt;br /&gt;
ReX : Dans les blocs de description de fichiers pas dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entrée standard, on le répartit dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, il faut appeler &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; pour chaque bloc de données à utiliser, aucune certitudes que les blocs libres soient en séquence.&lt;br /&gt;
&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs de données utilisés dans les blocs de description de ce fichier, les numéros étant écris sur deux octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Non cela doit se faire au fur et à mesure des appels à &amp;lt;code&amp;gt;findAvailableBlock&amp;lt;/code&amp;gt; et les numéros des blocs de données peuvent s'étaler sur les 16 blocs de description du fichier. Confusion totale sur ce point. Vous n'avez pas compris le mécanisme.&lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de données disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) offset=1040/8; else offset=0;&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que précédement sur les nombres 1024 et 1040.&lt;br /&gt;
&lt;br /&gt;
ReX : Vous n'avez toujours pas compris la contrainte sur la mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne vois pas ce que vous voulez faire avec &amp;lt;code&amp;gt;if (blockNum==1024) offset=1040/8; else offset=0;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Encore mieux : deux blocs de &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; en mémoire.&lt;br /&gt;
&lt;br /&gt;
ReX : Le &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; ne sort pas de la boucle externe.&lt;br /&gt;
&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de données correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
&lt;br /&gt;
ReX : Perdu. Ce n'est absolument pas la fonction de copie de fichiers d'un système de fichiers.&lt;br /&gt;
&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=912</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=912"/>
		<updated>2023-08-24T13:01:56Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Documents Rendus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas très propre (duplication de code) mais nous allons nous en contenter.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
ReX : OK. L'embryon de fonction &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; est correct, il manque juste le principal : la création des blocs de données. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) {&lt;br /&gt;
             offset=1040/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofilesystem.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Picofilesystem.c.tar&amp;diff=911</id>
		<title>Fichier:Picofilesystem.c.tar</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=Fichier:Picofilesystem.c.tar&amp;diff=911"/>
		<updated>2023-08-24T13:01:48Z</updated>

		<summary type="html">&lt;p&gt;Asellali : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;picofs&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=899</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=899"/>
		<updated>2023-08-23T16:44:36Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction findAvailableBlock */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie l'indice du premier bloc disponible. Je me sers de cette fonction dans la fonction TYPE.&lt;br /&gt;
 // Renvoie le premier bloc de donné disponible&lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 1024; blockNum &amp;lt; 1040; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==1024) {&lt;br /&gt;
             offset=1040/8;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return blockIndex; &lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=898</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=898"/>
		<updated>2023-08-23T16:36:38Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction setBlockAvailability */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndexInCard = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndexInCard&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le bloc de description&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndexInCard;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability==1) { // indisponible&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
         &lt;br /&gt;
     } else { // disponible&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
Cette fonction TYPE n'est pas encore au point. Je dois notamment créer la fonction findBlockAvailable qui renvoie le numéros du premier bloc disponible. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=897</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=897"/>
		<updated>2023-08-23T15:34:11Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndex = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndex&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le superbloc&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
Cette fonction TYPE n'est pas encore au point. Je dois notamment créer la fonction findBlockAvailable qui renvoie le numéros du premier bloc disponible. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         if (descriptionBuffer[offset]==0) {&lt;br /&gt;
             return;&lt;br /&gt;
         } else {&lt;br /&gt;
             writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=896</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=896"/>
		<updated>2023-08-23T15:25:10Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndex = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndex&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le superbloc&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
Cette fonction TYPE n'est pas encore au point. Je dois notamment créer la fonction findBlockAvailable qui renvoie le numéros du premier bloc disponible. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
Voici ma fonction CP, qui permet de créer une copie d'un fichier existant. L'idée est la suivante: pour copier un fichier, on doit créer un nouveau fichier et lui attribuer les mêmes blocs de descriptions que le fichier source. Ainsi, le fichier source et le fichier destination pointeront vers les mêmes blocs de données, et auront le même contenu.&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=895</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=895"/>
		<updated>2023-08-23T13:18:21Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction CP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndex = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndex&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le superbloc&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
Cette fonction TYPE n'est pas encore au point. Je dois notamment créer la fonction findBlockAvailable qui renvoie le numéros du premier bloc disponible. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
 void CP(const char *filesystem_path, const char *source_filename, const char *destination_filename) {&lt;br /&gt;
     unsigned char source_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char destination_filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char descriptionBuffer[BLOCK_SIZE];&lt;br /&gt;
     int destination_offset;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Recherche du fichier source&lt;br /&gt;
     int source_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, source_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier source&lt;br /&gt;
         if (strncmp((const char *)source_filenameBuffer, source_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             source_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (source_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier source \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Recherche d'un emplacement libre pour le fichier destination&lt;br /&gt;
     destination_offset = -1;&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, destination_filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (destination_filenameBuffer[0] == 0) {&lt;br /&gt;
             destination_offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (destination_offset == -1) {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer la copie de \&amp;quot;%s\&amp;quot;.\n&amp;quot;, source_filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Ecrit le nom de la copie dans le bloc de description&lt;br /&gt;
     writeBlock(destination_offset, 0, (const unsigned char *)destination_filename, strlen(destination_filename));&lt;br /&gt;
 &lt;br /&gt;
     // Copier les blocs de description associés au fichier source dans les blocs de description du fichier destination&lt;br /&gt;
     for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE_DESCRIPTION; i++) {&lt;br /&gt;
         if (i==0) {&lt;br /&gt;
             offset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset = 0;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         readBlock(source_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
         writeBlock(destination_offset+i, offset, descriptionBuffer, BLOCK_SIZE-offset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;La copie de \&amp;quot;%s\&amp;quot; sous le nom \&amp;quot;%s\&amp;quot; a été créée avec succès.\n&amp;quot;, source_filename, destination_filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=894</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=894"/>
		<updated>2023-08-23T12:33:31Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Semaine 7 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndex = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndex&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le superbloc&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
Cette fonction TYPE n'est pas encore au point. Je dois notamment créer la fonction findBlockAvailable qui renvoie le numéros du premier bloc disponible. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
== Semaine 7 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction CP ===&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=893</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=893"/>
		<updated>2023-08-22T15:09:27Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction findAvailableBlock */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndex = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndex&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le superbloc&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
Cette fonction TYPE n'est pas encore au point. Je dois notamment créer la fonction findBlockAvailable qui renvoie le numéros du premier bloc disponible. &lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=892</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=892"/>
		<updated>2023-08-22T14:59:36Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndex = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndex&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le superbloc&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
 &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Fonctionnement de la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* étape 1: on parcours les blocs de descriptions à la recherche d'un bloc disponible. Si on ne trouve pas de bloc disponible, on renvoie un message d'erreur, sinon on passe  à l&amp;quot;étape suivante. &lt;br /&gt;
* étape 2: Si on trouve un emplacement libre dans les blocs de disponibilité, on écrit le nom du fichier dans cet emplacement.&lt;br /&gt;
* étape 3: Ensuite, on lit le texte entré par l'utilisateur en entré standard, on le reparti dans des blocs de taille BLOCK_SIZE, on met à jour la disponibilité des blocs utilisés.&lt;br /&gt;
* étape 4: Enfin, on écrit les numéros des blocs utilisés dans les blocs de description de ce fichier, les numéros étant écrit sur deux octets. &lt;br /&gt;
&lt;br /&gt;
Cette fonction TYPE n'est pas encore au point. Je dois encore la modifier. &lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie le numéro du premier bloc disponible. Je l'utilise dans la fonction TYPE. &lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= 16; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==0) {&lt;br /&gt;
             offset=1040;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE-offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = (blockNum - 1) * 8 + byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return 1040 + blockIndex; // Ajouter 1041 pour obtenir l'indice réel du bloc&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
	<entry>
		<id>https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=891</id>
		<title>SE4 2022/2023 EC1</title>
		<link rel="alternate" type="text/html" href="https://wiki-se.plil.fr/mediawiki/index.php?title=SE4_2022/2023_EC1&amp;diff=891"/>
		<updated>2023-08-22T14:49:07Z</updated>

		<summary type="html">&lt;p&gt;Asellali : /* Fonction TYPE version 1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Objectifs =&lt;br /&gt;
&lt;br /&gt;
Il vous est demandé de : &lt;br /&gt;
* réaliser un micro système de fichiers ;&lt;br /&gt;
* le système de fichiers doit résider dans un fichier de 8 Mo ;&lt;br /&gt;
* le système de fichiers est géré par un exécutable obtenu à partir d'un programme C ;&lt;br /&gt;
* L'éxécutable prend deux arguments, le premier est le chemin du fichier dans lequel réside le système de fichiers, les paramètres suivants concernent l'action à appliquer sur le système de fichiers ;&lt;br /&gt;
* le micro système de fichier ne comporte qu'un répertoire : le répertoire principal, le répertoire principal peut comporter au maximum 64 fichiers, un fichier est caractérisé par un nom de 16 caractères au maximum et ses blocs de données, un fichier peut comporter au maximum 2040 blocs de données ;&lt;br /&gt;
* un bloc de données fait 256 octets et les blocs sont numérotés sur 2 octets ;&lt;br /&gt;
* les différentes actions possibles sur le système de fichiers sont :&lt;br /&gt;
** &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt; pour créer un fichier si possible, le nom du fichier suit la commande, le contenu du fichier est donné en entrée standard de l'exécutable ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt; pour afficher un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; pour détruire un fichier, le nom du fichier suit la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; pour renommer un fichier, les noms original et nouveau du fichier suivent la commande ;&lt;br /&gt;
** &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt; pour copier un fichier, les noms de l'original et de la copie du fichier suivent la commande ;&lt;br /&gt;
&lt;br /&gt;
= Matériel nécessaire =&lt;br /&gt;
&lt;br /&gt;
Un PC sous Linux.&lt;br /&gt;
&lt;br /&gt;
= Travail réalisé =&lt;br /&gt;
&lt;br /&gt;
== Semaine 1 ==&lt;br /&gt;
&lt;br /&gt;
ReX : attention, ce micro-système de fichiers est prévu pour un microcontrôleur, vos variables globales ne peuvent pas dépasser quelques centaines d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit, vous voulez dire le formatage du système de fichiers ?&lt;br /&gt;
&lt;br /&gt;
* création du programme programme.c contenant les différentes structures et les différentes fonctions. &lt;br /&gt;
* Piste d'amélioration: faire en sorte que la fonction CAT affiche le contenu exact des fichiers passés en argument.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le code fourni est un programme en langage C qui simule un système de fichiers basique. Ce programme permet aux utilisateurs d'effectuer diverses actions telles que créer, afficher, supprimer, renommer et copier des fichiers dans un système de fichiers simulé. Le système de fichiers est stocké dans un fichier binaire.&lt;br /&gt;
&lt;br /&gt;
ReX : vous n'avez pas tenu compte de la première remarque, vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&lt;br /&gt;
&lt;br /&gt;
ReX : vos structures utilisent des types entiers dont la taille n'est pas explicitée, utilisez les types de &amp;lt;code&amp;gt;stdint.h&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : la création de fichier n'est pas fonctionnelle, vous ne cherchez pas les blocs libres, vous ne copiez pas le contenu du fichier dans les blocs, même remarque pour toutes les autres fonctions.&lt;br /&gt;
&lt;br /&gt;
ReX : il manque les fonctions d'accès aux pages du système de fichiers.&lt;br /&gt;
&lt;br /&gt;
'''Explication du programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
Voici une brève explication des principaux éléments et fonctions du code :&lt;br /&gt;
&lt;br /&gt;
# Structures :&lt;br /&gt;
#* Fichier : Représente un fichier dans le système de fichiers. Il      contient un nom (nom) avec une longueur maximale de 16 caractères, un      tableau de numéros de bloc (blocs) où le contenu du fichier est stocké      (jusqu'à 2040 blocs), et le nombre de blocs utilisés par le fichier (nbBlocs).&lt;br /&gt;
#* Repertoire : Représente le répertoire principal du système de      fichiers. Il contient un tableau de fichiers (&amp;lt;code&amp;gt;fichiers&amp;lt;/code&amp;gt;) et le nombre de      fichiers dans le répertoire (&amp;lt;code&amp;gt;nbFichiers&amp;lt;/code&amp;gt;).&lt;br /&gt;
# Fonctions :&lt;br /&gt;
#* &amp;lt;code&amp;gt;chargerSystemeFichiers&amp;lt;/code&amp;gt; : Charge le système de fichiers à partir d'un      fichier binaire donné (chemin) dans une structure Repertoire.&lt;br /&gt;
#* &amp;lt;code&amp;gt;sauvegarderSystemeFichiers&amp;lt;/code&amp;gt; : Sauvegarde le système de fichiers stocké      dans la structure Repertoire dans un fichier binaire (chemin).&lt;br /&gt;
#* &amp;lt;code&amp;gt;creerFichier&amp;lt;/code&amp;gt; : Crée un nouveau fichier dans le système de fichiers      avec un nom et un contenu donnés. Le contenu du fichier est simulé en le      divisant en blocs.&lt;br /&gt;
#* &amp;lt;code&amp;gt;afficherFichier&amp;lt;/code&amp;gt; : Affiche le contenu d'un fichier avec le nom      spécifié.&lt;br /&gt;
#* &amp;lt;code&amp;gt;detruireFichier&amp;lt;/code&amp;gt; : Supprime un fichier avec le nom spécifié du système      de fichiers.&lt;br /&gt;
#* &amp;lt;code&amp;gt;renommerFichier&amp;lt;/code&amp;gt; : Renomme un fichier avec l'ancien nom spécifié en un      nouveau nom.&lt;br /&gt;
#* &amp;lt;code&amp;gt;copierFichier&amp;lt;/code&amp;gt; : Copie un fichier avec le nom spécifié en créant un      nouveau fichier avec le nom de copie spécifié.&lt;br /&gt;
# Fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; :&lt;br /&gt;
#* La fonction &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; est le point d'entrée du programme.&lt;br /&gt;
#* Elle prend des arguments en ligne de commande : &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt;      et &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;chemin_systeme_fichiers&amp;gt;&amp;lt;/code&amp;gt; est le chemin vers le fichier binaire      où le système de fichiers est stocké.&lt;br /&gt;
#* &amp;lt;code&amp;gt;&amp;lt;action&amp;gt;&amp;lt;/code&amp;gt; détermine quelle opération effectuer, comme &amp;lt;code&amp;gt;TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;,      &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MV&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;CP&amp;lt;/code&amp;gt;.&lt;br /&gt;
#* En fonction de l'action spécifiée, le programme appelle la fonction      correspondante pour effectuer l'opération souhaitée sur le système de      fichiers.&lt;br /&gt;
Remarque : Le code fourni une simulation basique d'un système de fichiers et de ses opérations, mais il n'interagit pas réellement avec un système de fichiers réel sur le disque.  &lt;br /&gt;
&lt;br /&gt;
'''Comment utiliser le programme programme.c'''&lt;br /&gt;
&lt;br /&gt;
étape 1: création du système de fichiers respectant le cahier des charges:&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=systeme_fichiers.bin bs=1M count=8&lt;br /&gt;
&lt;br /&gt;
étape 2: compilation du programme C:&lt;br /&gt;
&lt;br /&gt;
 gcc programme.c -o gestionnaire_fs&lt;br /&gt;
&lt;br /&gt;
étape 3: création d'un fichier dans le système de fichier:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin TYPE fichier1.txt&lt;br /&gt;
&lt;br /&gt;
-&amp;gt; entrer le texte en entrée standard&lt;br /&gt;
&lt;br /&gt;
étape 4: manipulation des différentes fonctions. Exemples:&lt;br /&gt;
&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CAT fichier1.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin CP fichier1.txt copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin RM copie.txt&lt;br /&gt;
 ./gestionnaire_fs systeme_fichiers.bin MV fichier1.txt fichier2.txt&lt;br /&gt;
&lt;br /&gt;
== Semaine 2 ==&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. Désolé de ne pas avoir suivi votre première remarque, je pensais avoir compris ce qu'il fallait faire mais je me rend compte que non. Je vais tout reprendre depuis le début afin de repartir sur de bonnes bases.&lt;br /&gt;
&lt;br /&gt;
'''Création du système de fichier avec la commande &amp;quot;dd&amp;quot;'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;A quoi sert la commande dd?&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; permet de copier tout ou partie d'un disque par blocs d'octets, indépendamment de la structure du contenu du disque en fichiers et en répertoires (source : [https://doc.ubuntu-fr.org/dd]). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Structure de la commande&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt; of=&amp;lt;cible&amp;gt; bs=&amp;lt;taille des blocs&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; = données à copier &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;cible&amp;lt;/code&amp;gt; = endroit où les copier&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; = input file &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;of&amp;lt;/code&amp;gt; = output file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bs&amp;lt;/code&amp;gt; = block size, habituellement une puissance de 2 supérieure ou égale à 512, représentant un nombre d'octets &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Choix de la commande&amp;lt;/u&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
Pour la source, on prends &amp;lt;code&amp;gt;/dev/zero&amp;lt;/code&amp;gt;: cela permet de créer un fichier rempli de 0. Ce fichier servira de base pour notre système de fichiers.&lt;br /&gt;
&lt;br /&gt;
Pour la cible, on va l'appeler &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/Code&amp;gt; : ce sera notre système de fichier.&lt;br /&gt;
&lt;br /&gt;
Pour la taille des blocs, on veut des blocs de données de 256 octets d'après l'enoncé. On va donc prendre &amp;lt;code&amp;gt;bs=256&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Enfin, on veut que le système de fichier réside dans un fichier de 8 Mo. On va donc ajouter &amp;lt;code&amp;gt;count=31250&amp;lt;/code&amp;gt;: cela indique que nous voulons écrire 32768 blocs de données dans le fichier (31250 * 256 octets = 8 Mo).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Résultat:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=31250&lt;br /&gt;
&lt;br /&gt;
Question pour M. Redon : j'ai ici essayé de respecter votre remarque &amp;quot;pour la création du système de fichiers la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; suffit&amp;quot;. Cependant, pour votre seconde remarque &amp;quot;vous chargez tout le superbloc et le répertoire racine, votre code ne convient pas.&amp;quot;, je ne suis pas sûr de comprendre où je fais cela: est-ce lors de la commande dd ou est-ce par la suite avec mon programme C? J'ai un peu modifié la commande dd comme vous pouvez le voir ci-dessus. Ai-je corrigé mon erreur avec cette nouvelle commande? J'ai essayé de justifier au maximum la commande dd que j'ai choisie.&lt;br /&gt;
&lt;br /&gt;
ReX : Pas de problème avec la commande &amp;lt;code&amp;gt;dd&amp;lt;/code&amp;gt; (mettez tous les extraits de code entre des balises &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;). Le problème est au niveau du programme C.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok je comprends mieux merci. Je vais donc reprendre le code étape par étape afin de mieux répondre au cahier des charges.&lt;br /&gt;
&lt;br /&gt;
Gestion du système de fichier par un programme C&lt;br /&gt;
&lt;br /&gt;
'''Création des structures'''&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un bloc de données&lt;br /&gt;
 &lt;br /&gt;
 struct DataBlock {&lt;br /&gt;
    uint8_t data[256]; // 256 octets pour chaque bloc de données&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un fichier&lt;br /&gt;
 &lt;br /&gt;
 struct File {&lt;br /&gt;
    char filename[17]; // 16 caractères pour le nom du fichier + 1 caractère null-terminator&lt;br /&gt;
    struct DataBlock data_blocks[2040]; // Tableau de blocs de données pour stocker le contenu du fichier&lt;br /&gt;
    uint16_t num_data_blocks; // Nombre de blocs de données utilisés par le fichier&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 // Structure pour représenter un répertoire&lt;br /&gt;
 &lt;br /&gt;
 struct Directory {&lt;br /&gt;
    struct File files[64]; // Tableau de fichiers pour le répertoire principal&lt;br /&gt;
    uint8_t num_files; // Nombre de fichiers dans le répertoire principal&lt;br /&gt;
 }; &lt;br /&gt;
&lt;br /&gt;
Modification faite : suite à votre remarque, j'ai explicité la taille des entiers grâce aux types de &amp;lt;code&amp;gt;stdint.h.&amp;lt;/code&amp;gt; (j'ai également mis les variables en anglais)&lt;br /&gt;
&lt;br /&gt;
ReX : Vous ne pouvez pas utiliser ces structures, une instanciation d'une de ces structure prend trop d'espace mémoire, vous devez faire sans structure. Par ailleurs la façon dont vous représentez vos fichiers ne convient pas, la description d'un fichier contient des numéros de blocs, pas les blocs eux-même. Faites aussi attention qu'un fichier soit décrit par un nombre entier de blocs.&lt;br /&gt;
&lt;br /&gt;
Question pratique: je n'arrive pas à mettre tout le code dans le même bloc comme vous l'avez fait ci-dessus dans l'étape 4 de la semaine 1. Je vois que c'est en format &amp;quot;préformaté&amp;quot; mais j'obtiens des blocs séparés lorsque j'applique ce format à mon code.&lt;br /&gt;
&lt;br /&gt;
ReX : j'ai corrigé, pour un code entier la syntaxe n'est pas la même (un espace en début de chaque ligne), la balise c'est uniquement pour de très courts extraits de code.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour lire un bloc de données à partir du fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; et le stocker dans un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).  &lt;br /&gt;
&lt;br /&gt;
Fonction:  &lt;br /&gt;
    &lt;br /&gt;
    #define BLOCK_SIZE 256&lt;br /&gt;
    // Fonction pour lire un bloc de données&lt;br /&gt;
    void readBlock(unsigned int num, int offset, unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fread(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc à lire. Chaque bloc contient 256 octets (1 bloc = 256 octets).&lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer la lecture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères où les données lues seront stockées.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture binaire (&amp;lt;code&amp;gt;&amp;quot;rb&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture dans le fichier à l'endroit approprié pour commencer la lecture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fread&amp;lt;/code&amp;gt; pour lire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du fichier et les stocker dans le tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note : Le paramètre &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est utilisé pour spécifier à partir de quel octet du bloc on souhaite commencer la lecture. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est égal à 0, la lecture commencera depuis le début du bloc. Si &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; est différent de 0, la lecture commencera à l'octet spécifié.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Remarque: dans votre mail, vous définissez &amp;quot;readBlock(unsigned int num,int offset,unsigned storage,int size)&amp;quot;: storage n'est alors pas un pointeur vers un tableau de caractère. Je me suis donc permis de faire la modification.&lt;br /&gt;
&lt;br /&gt;
ReX : OK pour la fonction, pas la peine d'en mettre autant dans le Wiki pour une fonction aussi simple.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;''' ===&lt;br /&gt;
Cette fonction est utilisée pour écrire un bloc de données dans le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; à partir d'un tableau de caractères (&amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonction:&lt;br /&gt;
&lt;br /&gt;
    // Fonction pour écrire un bloc de données&lt;br /&gt;
    void writeBlock(unsigned int num, int offset, const unsigned char *storage, int size) {&lt;br /&gt;
        FILE *file = fopen(&amp;quot;filesystem.bin&amp;quot;, &amp;quot;rb+&amp;quot;);&lt;br /&gt;
        if (file == NULL) {&lt;br /&gt;
            perror(&amp;quot;Erreur lors de l'ouverture du fichier&amp;quot;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        fseek(file, num * BLOCK_SIZE + offset, SEEK_SET);&lt;br /&gt;
        fwrite(storage, 1, size, file);&lt;br /&gt;
        fclose(file);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Paramètres :&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; : Numéro du bloc où écrire. &lt;br /&gt;
* &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; : Décalage (en octets) à partir du début du bloc pour commencer l'écriture.&lt;br /&gt;
* &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; : Pointeur vers un tableau de caractères contenant les données à écrire dans le fichier.&lt;br /&gt;
* &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; : Taille du tableau de caractères &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* La fonction commence par ouvrir le fichier &amp;lt;code&amp;gt;filesystem.bin&amp;lt;/code&amp;gt; en mode lecture et écriture binaire (&amp;lt;code&amp;gt;&amp;quot;rb+&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise &amp;lt;code&amp;gt;fseek&amp;lt;/code&amp;gt; pour positionner le curseur de lecture/écriture dans le fichier à l'endroit approprié pour commencer l'écriture du bloc spécifié (&amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt;) à partir de l'offset (&amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Elle utilise ensuite &amp;lt;code&amp;gt;fwrite&amp;lt;/code&amp;gt; pour écrire &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; octets à partir du tableau &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt; dans le fichier.&lt;br /&gt;
* Enfin, elle ferme le fichier avec &amp;lt;code&amp;gt;fclose&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Même remarque que pour la fonction précédente.&lt;br /&gt;
&lt;br /&gt;
'''Etape 4: test des fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; dans le main'''&lt;br /&gt;
    // Exemple de fonction principale pour tester les opérations de lecture et d'écriture&lt;br /&gt;
    int main() {&lt;br /&gt;
        unsigned char data[BLOCK_SIZE];&lt;br /&gt;
        // Test de la fonction readBlock&lt;br /&gt;
        readBlock(0, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 0, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        // Test de la fonction writeBlock&lt;br /&gt;
        unsigned char newData[BLOCK_SIZE] = {&lt;br /&gt;
            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,&lt;br /&gt;
            // ... Autres données du bloc ...&lt;br /&gt;
        };&lt;br /&gt;
        writeBlock(1, 0, newData, BLOCK_SIZE);&lt;br /&gt;
        // Lecture du bloc nouvellement écrit pour vérifier&lt;br /&gt;
        readBlock(1, 0, data, BLOCK_SIZE);&lt;br /&gt;
        printf(&amp;quot;Block 1, offset 0: &amp;quot;);&lt;br /&gt;
        for (int i = 0; i &amp;lt; BLOCK_SIZE; i++) {&lt;br /&gt;
            printf(&amp;quot;%02x &amp;quot;, data[i]);&lt;br /&gt;
        }&lt;br /&gt;
        printf(&amp;quot;\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Fonctionnement :&lt;br /&gt;
&lt;br /&gt;
* On déclare tout d'abord un tableau de caractères &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; de taille &amp;lt;code&amp;gt;BLOCK_SIZE&amp;lt;/code&amp;gt; pour stocker les données lues du bloc.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (0, 0, data, BLOCK_SIZE) pour lire le premier bloc du fichier (&amp;lt;code&amp;gt;num=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;) et stocker les données dans &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Ensuite, la fonction &amp;lt;code&amp;gt;printf&amp;lt;/code&amp;gt; est utilisée pour afficher les données lues du bloc (&amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt;) en format hexadécimal.&lt;br /&gt;
* Ensuite, un nouveau tableau de caractères &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; est créé avec des données spécifiques pour tester la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
* La fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; est appelée avec les arguments (1, 0, newData, BLOCK_SIZE) pour écrire le tableau &amp;lt;code&amp;gt;newData&amp;lt;/code&amp;gt; dans le deuxième bloc du fichier (&amp;lt;code&amp;gt;num=1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;offset=0&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Enfin, la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; est appelée à nouveau pour lire le deuxième bloc nouvellement écrit et afficher les données lues en format hexadécimal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Question générale : ce que j'avais la première semaine n'est plus forcément d'actualité. Puis-je supprimer les choses qui ne le sont plus afin d'alléger la page ou préférez-vous que je laisse? &lt;br /&gt;
&lt;br /&gt;
ReX : Laissez.&lt;br /&gt;
&lt;br /&gt;
Pour la suite : j'ai donc pour l'instant crée deux fonctions, l'une permettant la lecture et l'autre l'écriture d'un bloc, de manière à économiser la mémoire. Pour la suite, je vais essayer de créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; en utilisant  la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est le début du projet. Mais si vous n'avez pas une bonne description de fichier cela ne donnera rien. Voir remarques plus haut.&lt;br /&gt;
&lt;br /&gt;
'''Etape 5: fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt;'''&lt;br /&gt;
&lt;br /&gt;
Objectif: créer la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; avec la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
Question: Souhaitez-vous la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; classique, c'est à dire la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; qui affiche simplement le nom des fichiers présent dans le répertoire ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui. Tu peux ajouter la taille si tu trouves cela trop simple. &lt;br /&gt;
&lt;br /&gt;
Piste : si c'est ce que vous voulez:&lt;br /&gt;
&lt;br /&gt;
* il va tout d'abord falloir que je crée des fichiers, un fichier étant composé d'un nom et de blocs (création d'une fonction createFile)&lt;br /&gt;
* Il faudra ensuite que je stocke ces fichiers dans le répertoire (création d'une fonction addFileToDirectory par exemple)&lt;br /&gt;
* enfin, il faudra que j'affiche le nom des fichiers. Pour cela, il faudra que je parcours le répertoire (structure &amp;quot;Directory&amp;quot;), puis que pour chaque fichier présent dans le répertoire que j'affiche son nom (création de la fonction LS)&lt;br /&gt;
&lt;br /&gt;
Je devrais surement utiliser la fonction readBlock afin de transférer les blocs dans le fichier au travers de la variable &amp;quot;storage&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
ReX : Créer des fichiers n'est pas nécessaire tout de suite je verrais bien si ton code est bon sans test. Laisse tomber &amp;lt;code&amp;gt;createFile&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;addFileToDirectory&amp;lt;/code&amp;gt; pour l'instant.&lt;br /&gt;
&lt;br /&gt;
ReX : Ton algorithme ne fonctionne pas pour un microcontrôleur où il faut économiser la mémoire, tu ne peux pas t'aider de structures. Il faudra que tu charges les noms et seulement les noms, pour la taille il faudra se baser sur le nombre de blocs.&lt;br /&gt;
&lt;br /&gt;
'''Etape 6: rectification du code suite à vos remarques'''&lt;br /&gt;
&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* suppression des structures afin d’économiser de la mémoire.&lt;br /&gt;
&lt;br /&gt;
* le problème quant à la description des fichiers est normalement résolu puisque plus de structures. On ne charge plus les blocs mais seulement les noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : Non car si les noms ne sont pas répartis de façon régulière dans les blocs de 256 octets tu vas avoir du mal à les charger. Mais écrit la fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; et tu verras ce que je veux dire.&lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté deux nouvelles fonctions:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;void readFileName(unsigned int file_num, char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet de lire le nom du fichier associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle stocke le nom du fichier lu dans le tableau &amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;lt;code&amp;gt;void writeFileName(unsigned int file_num, const char *file_name)&amp;lt;/code&amp;gt;: Cette fonction permet d'écrire le nom du fichier dans le système de fichiers, associé au numéro de fichier donné (&amp;lt;code&amp;gt;file_num&amp;lt;/code&amp;gt;). Elle prend en entrée le nom du fichier à écrire (&amp;lt;code&amp;gt;file_name&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Suite: si vous validez cette base, je pourrai passer à la création de la fonction LS.&lt;br /&gt;
&lt;br /&gt;
ReX : tu peux y aller. Je ne vois pas le code des tes deux fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Voici le code des fonctions &amp;lt;code&amp;gt;readFileName&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeFileName&amp;lt;/code&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
'''Fonction readFileName:''' &lt;br /&gt;
 // Fonction pour lire le nom du fichier &lt;br /&gt;
 void readFileName(unsigned int file_num, char *file_name) {&lt;br /&gt;
      readBlock(file_num, 0, (unsigned char *)file_name, MAX_FILENAME_LENGTH); &lt;br /&gt;
      file_name[MAX_FILENAME_LENGTH] = '\0'; // Ajout du caractère null-terminator pour former une chaîne de caractères &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Non, aucune raison que le fichier de numéro n soit au bloc n. Dessine la représentation d'un fichier sur le SF en comptant les octets si cela peut aider.&lt;br /&gt;
&lt;br /&gt;
'''Fonction writeFileName:''' &lt;br /&gt;
 // Fonction pour écrire le nom du fichier&lt;br /&gt;
 void writeFileName(unsigned int file_num, const char *file_name) {&lt;br /&gt;
     writeBlock(file_num, 0, (const unsigned char *)file_name, MAX_FILENAME_LENGTH);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Faux et inutile pour l'instant. Problème avec la constante MAX_FILENAME_LENGTH.&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:'''&lt;br /&gt;
 // Fonction LS pour afficher les fichiers présents dans le système de fichiers&lt;br /&gt;
 void LS(const char *filesystem_path) {&lt;br /&gt;
     FILE *file = fopen(filesystem_path, &amp;quot;rb&amp;quot;);&lt;br /&gt;
     if (file == NULL) {&lt;br /&gt;
         perror(&amp;quot;Erreur lors de l'ouverture du fichier système&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     uint16_t num_files;&lt;br /&gt;
     fread(&amp;amp;num_files, sizeof(uint16_t), 1, file); // Lecture du nombre de fichiers dans le système&lt;br /&gt;
     char filename[17];&lt;br /&gt;
     printf(&amp;quot;Fichiers présents dans le système de fichiers:\n&amp;quot;);&lt;br /&gt;
     for (int i = 0; i &amp;lt; num_files; i++) {&lt;br /&gt;
         readFileName(i, filename); // Lecture du nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename); // Affichage du nom du fichier&lt;br /&gt;
     }&lt;br /&gt;
     fclose(file);&lt;br /&gt;
 }&lt;br /&gt;
La fonction &amp;lt;code&amp;gt;LS&amp;lt;/code&amp;gt; ouvre le fichier système, lit le nombre de fichiers qu'il contient, puis affiche les noms des fichiers un par un, chacun sur une ligne séparée.&lt;br /&gt;
&lt;br /&gt;
ReX : Il y a le nombre de fichiers dans ton superbloc ? Un dessin du format du superbloc avec les numéros des octets ?&lt;br /&gt;
&lt;br /&gt;
ReX : Tout accès au système de fichiers doit se faire avec les deux fonctions &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Semaine 3 ==&lt;br /&gt;
Question 1: cela fait plusieurs fois que vous mentionnez dans le wiki un &amp;quot;superbloc&amp;quot;. Celui-ci n'étant pas clairement défini dans le sujet, je me demande s'il s'agit du bloc crée grâce à la fonction dd, c'est à dire que le superbloc serait en faite le bloc constitué des 31250 blocs de taille 256 octets, où s'il s'agit d'un bloc qui vient en entête, celui contenant alors des informations décrivant le système de fichier (les noms de fichiers...). &lt;br /&gt;
&lt;br /&gt;
ReX : Pour ton pico système de fichiers, le superbloc consiste en les premiers blocs (de 256 octets) qui définissent les 64 fichiers possibles.&lt;br /&gt;
&lt;br /&gt;
Proposition de structure: on pourrait réserver les premiers blocs du système de fichiers aux noms de fichiers ainsi qu'aux numéros des blocs correspondant à chaque fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui c'est évident.&lt;br /&gt;
&lt;br /&gt;
On sait que les noms de fichiers font au maximum 16 caractères + 1 caractère pour le '\0' (donc 17 octets car 1 char=1 octet).&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 16 octets suffisent, des '\0' en fin de nom uniquement si le nom fait moins de 16 caractères.&lt;br /&gt;
&lt;br /&gt;
On sait également qu'un fichier contient au maximum 2040 blocs, chaque bloc étant numéroté sur 2 octets. On pourrait donc avoir en début du système de fichier: 17 octets+2 octets*2040 blocs = 4097 octets pour la description d'un fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 4096 octets soit 16 blocs de 256.&lt;br /&gt;
&lt;br /&gt;
Or d'après l'une de vos remarques dans le wiki, un fichier doit être décrit par un nombre entier de blocs. Pour un fichier, il nous faudra donc 4097/256=16.004 soit 17 blocs. Il peut y avoir jusqu'à 64 fichiers dans le répertoire, il nous faudra donc 17 blocs*64 fichiers= 1088 blocs pour la description des fichiers. &lt;br /&gt;
&lt;br /&gt;
ReX : Non 1024 blocs de 256 octets dans le superbloc. &lt;br /&gt;
&lt;br /&gt;
Ainsi, pour la fonction LS, il suffira de lire les premiers caractères tous les 17 blocs ( du premier caractère au caractère '\0'). &lt;br /&gt;
&lt;br /&gt;
ReX : Non, tous les 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Question 2: Ne faudrait-il pas également stocker quelque part le nombre de fichier qu'il y a dans le répertoire afin de savoir jusqu'à quel bloc la fonction LS doit aller ?&lt;br /&gt;
&lt;br /&gt;
ReX : Non, un fichier dont le nom n'est constitué que de '\0' est réputé ne pas exister.&lt;br /&gt;
&lt;br /&gt;
Question 3: on a donc vu que les 1088 premiers blocs au maximum serviraient à la description du système de fichier. Il reste donc 31250-1088=30132 blocs dans le système de fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, 32768-1024=31744 blocs.&lt;br /&gt;
&lt;br /&gt;
Comment utiliser ces blocs? Ces blocs doivent-ils stocker le contenu des fichiers ?&lt;br /&gt;
&lt;br /&gt;
ReX : Oui, c'et évident.&lt;br /&gt;
&lt;br /&gt;
En effet, avec la fonction TYPE, nous allons créer des fichiers et ces fichiers devront être stockés quelque part. Cependant, étant donné que ce pico système de fichiers est prévu pour un microcontrôleur, je ne sais pas si c'est le contenu des fichiers qui doit être stocké dans les blocs ou autre chose (peut être l'adresse des fichiers, le fichiers se trouvant autre part). En effet, je me dis que si un fichier est très volumineux, il ne pourra pas rentrer dans le système de fichier, ce dernier étant composé d'un nombre limité de blocs, et les blocs étant eux même limité en nombre d'octets.&lt;br /&gt;
&lt;br /&gt;
ReX : Je ne comprend pas ton problème. De tout façon comme dit plus haut, les 31744 blocs suivant le superbloc doivent contenir les données des fichiers.&lt;br /&gt;
&lt;br /&gt;
Désolé de poser des questions peut être basique aussi tard, mais je pense qu'une fois que j'aurai ces réponses, cela ira beaucoup mieux pour la suite. Merci d'avance pour vos réponses.&lt;br /&gt;
&lt;br /&gt;
ReX : Les questions sont effectivement triviales et il est effectivement inquiétant que voir que la travail n'avance pas.&lt;br /&gt;
&lt;br /&gt;
Amine: merci pour vos corrections. &lt;br /&gt;
&lt;br /&gt;
D'après votre commentaire &amp;quot;32768-1024=31744 blocs&amp;quot;, j'en déduis qu'il faut que je modifie ma commande dd (qui est actuellement &amp;quot;dd if=/dev/zero of=filesystem.bin bs=256 count=31250&amp;quot; pour avoir le bon filesystem). &lt;br /&gt;
&lt;br /&gt;
ReX : Je comprends pas d'où tu sors le 31250. D'autant plus que la commande ci-dessous est bonne.&lt;br /&gt;
&lt;br /&gt;
Amine : 31250 car 31250 blocs * 256 octets = 8 Mo.&lt;br /&gt;
&lt;br /&gt;
ReX : Haaaa je vois tu utilises le système métrique international où le mégaoctet vaut 10^6 octets, sauf qu'aucun informaticien n'utilisera cette norme hors sol. Quand je parle de 8 Mo c'est 8x1024x1024 octets. Tout simplement parce qu'une puce mémoire de 8 Mo c'est bien 8x1024x1024 octets.&lt;br /&gt;
&lt;br /&gt;
Amine: D'accord merci pour l'information !&lt;br /&gt;
&lt;br /&gt;
'''Nouvelle commande dd:''' &lt;br /&gt;
&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Fonction LS:''' &lt;br /&gt;
&lt;br /&gt;
Dans notre structure du système de fichier, le superbloc est constitué de 1024 blocs (16 blocs * 64 fichiers), un fichier étant décrit par 16 blocs. Le nom du fichier est donc écrit au début de tous les blocs multiples de 16. Par exemple, le nom du premier fichier est dans les 16 premiers octets du premier bloc, le nom du 2ème fichier est dans les 16 premiers octets du 32ème bloc et ainsi de suite, tant que des fichiers existent. Lorsque qu'il n'y a plus de fichier, le nom du premier caractère du bloc multiple de 16 est un 0. &lt;br /&gt;
&lt;br /&gt;
Voici le code:&lt;br /&gt;
 // Fonction pour lister les noms de fichiers présents dans le système de fichiers&lt;br /&gt;
  void LS() {&lt;br /&gt;
      unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
      int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
      for (int blockNum = 1; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc est vide&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             break; // Plus de fichiers à lire&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         char filename[MAX_FILENAME_LENGTH];&lt;br /&gt;
         memcpy(filename, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Afficher le nom du fichier&lt;br /&gt;
         printf(&amp;quot;%s\n&amp;quot;, filename);&lt;br /&gt;
         fileCount++;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Tu supposes que si un fichier a un nom vide, les suivants auront aussi un nom vide. C'est possible mais dans ce cas la commande &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; ca être plus compliquée à écrire.&lt;br /&gt;
&lt;br /&gt;
ReX : Tu ne sembles pas comprendre que la mémoire d'un microcontrôleur est limitée. Pourquoi lire le premier bloc de description d'un fichier en entier ? Dit autrement c'est quoi l'intérêt de lire 256 octets alors que 16 suffisent ? &lt;br /&gt;
&lt;br /&gt;
ReX : Pourquoi tu ne lis pas le premier fichier ? Autrement dit pourquoi décaler tout d'un bloc ?&lt;br /&gt;
&lt;br /&gt;
Amine: Merci pour vos remarques. J'ai apporté les modifications à LS dans la section &amp;quot;Semaine 4&amp;quot; du wiki. &lt;br /&gt;
&lt;br /&gt;
'''Réflexion par rapport aux autres fonctions:'''&lt;br /&gt;
&lt;br /&gt;
J'ai créé les fonctions TYPE et CAT mais il y a malheureusement un problème pour l'instant. Vous pouvez les retrouver en pièce jointe dans l'archive du fichier programme.c.&lt;br /&gt;
&lt;br /&gt;
Le problème que j'ai est que lorsque j'affiche le contenu du fichier créé avec TYPE, j'obtiens plein de caractères spéciaux. Par exemple, je créé le fichier &amp;quot;mon_fichier.txt&amp;quot; avec la fonction TYPE, et je mets en entré standard &amp;quot;hello&amp;quot;. Ensuite, je veux afficher le contenu de ce fichier grâce à la fonction CAT. Cependant, ce qui s'affiche dans le terminal n'est pas ce que je veux. De la même manière, lorsque je fais la commande &amp;quot;cat filesystem.bin&amp;quot; dans le terminal, c'est la même chose s'affiche, des donnés parasites. &lt;br /&gt;
&lt;br /&gt;
ReX : Avant même de lire ton code je vais te poser la question de savoir comment tu récupères un bloc libre ? Quel algorithme tu utilises. Personnellement je ne sais pas faire sans ajouter au superbloc un tableau bit à bit des blocs libres. Pour avoir un bit pour chaque bloc du système de fichiers, il faut 32768/8=4096 octets soit 16 blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais donc ajouter ce tableau de 16 blocs à la suite de mes premiers 1024 blocs servant à la description de fichier. Le superbloc fera maintenant 1024+16=1040 blocs (plus de détail à la fonction RM de la semaine 4).&lt;br /&gt;
&lt;br /&gt;
Question 1: est ce que la fonction CAT que je dois créer doit renvoyer la même chose que &amp;quot;cat filesystem.bin&amp;quot; ?&lt;br /&gt;
&lt;br /&gt;
ReX : Je préfère ne pas répondre tellement la question montre un manque de réflexion.&lt;br /&gt;
&lt;br /&gt;
Question 2: comment savoir combien de blocs doivent etre attribué à un fichier? Par exemple, si je créé un fichier &amp;quot;mon_fichier.txt&amp;quot; et que je mets en entrée standard le texte &amp;quot;hello&amp;quot;, un seul bloc suffi pour stocker ce texte. Cependant, si j'avais mis beaucoup de texte en entrée standard, il aurait fallu plus de blocs. Doit-on calculer la taille de l'entrée standard ou doit-on attribuer toujours le meme nombre de blocs à un fichier? Peut-etre ainsi attribuer 2040 blocs par fichier, meme s'il n'en utilise que 1.&lt;br /&gt;
&lt;br /&gt;
ReX : Là encore c'est une question stupéfiante tellement la réponse est évidente. Il suffit de lire les données sur l'entrée standard et de passer au bloc de données suivant dès que le bloc courant est rempli. La question à poser c'était de se demander comment il est possible d'avoir la taille exacte du fichier pour un &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Il est uniquement possible de l'avoir à 256 octets près puisque rien n'indique si le dernier block est vide. Le mieux aurait été de prévoir 4 octets dans la description d'un fichier pour stocker la taille. En l'espèce on considérera que les fichiers sont des fichiers ASCII et qu'ils seront terminés par des &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; qui ne seront pas affichés.&lt;br /&gt;
&lt;br /&gt;
== Semaine 4 ==&lt;br /&gt;
&lt;br /&gt;
Voici un bilan de ce que j'ai fait à ce stade du projet:&lt;br /&gt;
&lt;br /&gt;
* j'ai choisi une structure du système de fichier&lt;br /&gt;
* j'ai créé les fonctions readBlock et writeBlock permettant de lire et d'écrire des blocs &lt;br /&gt;
* j'ai crée la fonction LS permettant d'afficher le nom des fichiers présents dans le système de fichiers&lt;br /&gt;
* j'ai programmer un main permettant d'utiliser les fonctions (LS, TYPE...) depuis le terminal &lt;br /&gt;
* j'ai réflechi aux fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
Actuellement, je suis en train de créer les fonctions TYPE et CAT.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction LS''' ===&lt;br /&gt;
 void LS() {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileCount = 0;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir tous les 16 blocs de 0 jusqu'à MAX_FILES_IN_DIRECTORY&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le nom de fichier est vide&lt;br /&gt;
         if (buffer[0] != 0) {&lt;br /&gt;
 &lt;br /&gt;
             // Afficher le nom du fichier&lt;br /&gt;
             printf(&amp;quot;%s\n&amp;quot;, buffer);&lt;br /&gt;
             fileCount++;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if (fileCount == 0) {&lt;br /&gt;
         printf(&amp;quot;Aucun fichier trouvé.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Suite à vos remarques, j'ai effectué les modifications suivantes de la fonction LS:&lt;br /&gt;
&lt;br /&gt;
* Je ne suppose plus que si un fichier a un nom vide, les autres auront aussi un nom vide. &lt;br /&gt;
* Je ne lis plus les 256 octets mais seulement les 16 premiers octets car cela suffit. &lt;br /&gt;
* Je ne lisais en effet pas le premier bloc. Je pensais que le premier bloc était d'indice 1 mais ce n'est pas le cas.&lt;br /&gt;
&lt;br /&gt;
ReX : Ouiiii ! Une fonction correcte. Passe à &amp;lt;code&amp;gt;RM&amp;lt;/code&amp;gt; maintenant, c'est la plus facile à faire concernant l'image bit à bit des blocs libres.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability:'''&lt;br /&gt;
&lt;br /&gt;
Comme vous l'avez indiqué dans votre remarque, il faut un tableau dans le superbloc qui nous permettra de connaitre la disponibilité bit par bit de chaque bloc. Sachant qu'il y a dans notre système de fichiers 32768 blocs, et qu'il faut 1 bit par bloc, nous avons besoin de 32768 bits, soit 32768/8=4096 octets soit 4096/256=16 blocs. Notre superbloc sera donc comme suit: les 1024 premiers blocs servent à la description des fichiers, c'est à dire à leur nom suivi des numéros de blocs qui leur sont associés, puis ces 1024 blocs sont suivi de 16 blocs listant la disponibilité de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Bien résumé.&lt;br /&gt;
&lt;br /&gt;
Nous allons tout d'abord écrire la fonction &amp;quot;setBlockAvailability&amp;quot; prenant en paramètre le numéro du bloc à traiter (&amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt;) et la disponibilité souhaitée pour ce bloc (&amp;lt;code&amp;gt;availability&amp;lt;/code&amp;gt;). Cette fonction permet de marquer la disponibilité d'un bloc spécifique dans le système de fichiers. Nous utiliserons la convention suivante: un bloc disponible sera marqué par un 1 tandis qu'un bloc non disponible par un 0.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'index du byte et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = blockNum % 8;&lt;br /&gt;
 &lt;br /&gt;
     // Lire le byte existant du bloc de disponibilité des blocs&lt;br /&gt;
     unsigned char buffer[1];&lt;br /&gt;
     readBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire le byte mis à jour dans le bloc de disponibilité des blocs&lt;br /&gt;
     writeBlock(SUPERBLOCK_START_BLOCK + byteIndex, 0, buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Un tableau de un octet c'est un octet (variable &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Amine: je vais utiliser un &amp;lt;code&amp;gt;unsigned char buffer.&amp;lt;/code&amp;gt; Je suis conscient qu'un char vaut un octet mais je ne pense pas qu'il y ait un type de donnée de la taille d'un bit, c'est pourquoi je travaille avec un octet mais je modifie les bits de cet octet grâce aux algorithmes. &lt;br /&gt;
&lt;br /&gt;
ReX : Il faut bien que tu travailles sur un octet vu que l'état des blocs est stocké sous la forme d'octets. Je disais juste qu'un tableau de 1 élément n'a pas d'intérêt par rapport à l'élément lui-même.&lt;br /&gt;
&lt;br /&gt;
Amine: c'est vrai, modification faite.&lt;br /&gt;
&lt;br /&gt;
ReX : Non il faut calculer le numéro du bloc avant de faire le &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: ok je vais calculer le numéro de bloc avant.&lt;br /&gt;
&lt;br /&gt;
ReX : La mise à jour du bit est correcte mais le block et le déplacement dans le block ne sont pas correctement calculés.&lt;br /&gt;
&lt;br /&gt;
Amine: je vais vous expliquer le raisonnement que j'avais. Prenons un exemple concret, imaginons que je veuille marquer le bloc 1030 comme disponible: &lt;br /&gt;
&lt;br /&gt;
# Calcul de l'index de l'octet et du bit offset :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum&amp;lt;/code&amp;gt; = 1030&lt;br /&gt;
#* Index du byte = 1030 / 8 = 128&lt;br /&gt;
#* Bit offset = 1030 % 8 = 6&lt;br /&gt;
# Lecture de l'octet existant de disponibilité:&lt;br /&gt;
#* Nous lisons l'octet existant à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
# Mise à jour du bit de disponibilité :&lt;br /&gt;
#* Nous voulons marquer le bloc 1030 comme disponible, donc nous utilisons le masque &amp;lt;code&amp;gt;(1 &amp;lt;&amp;lt; 6)&amp;lt;/code&amp;gt; pour définir le bit 6 à 1 dans l'octet. Le résultat sera, par exemple, &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Écriture du byte mis à jour :&lt;br /&gt;
#* Nous écrivons le byte mis à jour &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt; à l'index 128 dans les blocs de disponibilité.&lt;br /&gt;
&lt;br /&gt;
ReX : Ben non, un vrai exemple :&lt;br /&gt;
* Il faut prendre un n° de bloc plus grand : 3072 ;&lt;br /&gt;
* Numéro d'octet dans la carte des blocs libres : 3072/8=384 ;&lt;br /&gt;
* Numéro du bloc dans la carte des blocs libres : 384/256=1 ;&lt;br /&gt;
* Numéro du bit &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; dans l'octet n° 384-256=128 du bloc 1 : 3072%8=0 ;&lt;br /&gt;
* Il faut donc lire l'octet &amp;lt;code&amp;gt;o&amp;lt;/code&amp;gt; de numéro 128 du bloc 1, puis modifier cet octet par &amp;lt;code&amp;gt;o |= (1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ou  &amp;lt;code&amp;gt;o &amp;amp;= ~(1&amp;lt;&amp;lt;b)&amp;lt;/code&amp;gt; ;&lt;br /&gt;
* Enfin il faut écrire l'octet modifié dans le bloc 1.&lt;br /&gt;
Amine: merci pour cet exemple! J'ai compris d'où vient mon erreur. Voir fonction setBlockAvailability version 3.&lt;br /&gt;
&lt;br /&gt;
Remarque: par convention, j'apellerai dans la suite de ce projet &amp;quot;premier superbloc&amp;quot; le superbloc correspondant à la description des fichiers, c'est à dire les 1024 premiers blocs, et j'appellerai &amp;quot;second superbloc&amp;quot; les 16 blocs qui suivent servant à décrire la disponibilité des blocs (du bloc 1024 au bloc 1039 inclu). Le reste des blocs servira à stocker les données. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, le superblc est l'ensemble des informations hors blocs de données, tu ne peux pas utiliser un vocabulaire au hasard. Parle de blocs de description des fichiers ou de carte des blocs libres.&lt;br /&gt;
&lt;br /&gt;
Amine: ok&lt;br /&gt;
&lt;br /&gt;
Je pense que le problème qui se pose est que l'indice du bit dans le second superbloc ne correspond pas à l'indice du bloc dans le système de fichier. Par exemple, nous voudrions que si le bloc 1030 est disponible dans le système de fichier, alors le bit numéro 1030 du deuxième superbloc soit à 1, ce qui n'est pas le cas ici. En effet, on se trouve bien dans le bon octet avec ma méthode mais l'écriture du bit se fait de la droite vers la gauche alors qu'on voudrait l'inverse. Ainsi, si le 6ème bit de l'octet doit être à 1, alors il faudrait qu'on obtienne &amp;lt;code&amp;gt;00000100&amp;lt;/code&amp;gt; et non &amp;lt;code&amp;gt;00100000.&amp;lt;/code&amp;gt; L'indice du bit coinciderait ainsi avec le numéro du bloc. &lt;br /&gt;
&lt;br /&gt;
ReX : Non, réfléchit à nouveau.&lt;br /&gt;
&lt;br /&gt;
Voir plus bas la nouvelle version de setBlockAvailability.&lt;br /&gt;
&lt;br /&gt;
Explication de l'algorithme pour mettre le bit à 1 ou 0:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] |= (1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur OR bit à bit (&amp;lt;code&amp;gt;|=&amp;lt;/code&amp;gt;) pour activer (mettre à 1) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans le premier octet (&amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;). Cela se fait en décalant le bit 1 vers la gauche de &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; positions, puis en effectuant une opération OR bit à bit avec le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Cette opération modifie uniquement le bit ciblé, laissant les autres bits inchangés.&lt;br /&gt;
&lt;br /&gt;
ReX : Oui ça c'est bon.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;buffer[0] &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&amp;lt;/code&amp;gt; : Cette ligne utilise l'opérateur AND bit à bit (&amp;lt;code&amp;gt;&amp;amp;=&amp;lt;/code&amp;gt;) pour désactiver (mettre à 0) le bit spécifié par &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt; dans &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;. Pour ce faire, l'expression &amp;lt;code&amp;gt;~(1 &amp;lt;&amp;lt; bitOffset)&amp;lt;/code&amp;gt; est utilisée pour créer un masque où tous les bits sont à 1, sauf celui correspondant à &amp;lt;code&amp;gt;bitOffset&amp;lt;/code&amp;gt;, qui est à 0. En effectuant ensuite une opération AND bit à bit entre le masque et le contenu actuel de &amp;lt;code&amp;gt;buffer[0]&amp;lt;/code&amp;gt;, on met à 0 le bit ciblé sans affecter les autres bits.&lt;br /&gt;
&lt;br /&gt;
ReX : Ca aussi.&lt;br /&gt;
&lt;br /&gt;
'''Fonction setBlockAvailability version 2''':&lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
     // Calculer l'indice de l'octet et le bit offset correspondant&lt;br /&gt;
     int byteIndex = blockNum / 8;&lt;br /&gt;
     int bitOffset = 7 - (blockNum % 8);  // Inversion de l'ordre des bits&lt;br /&gt;
 &lt;br /&gt;
     // Calculer le numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + byteIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, 0, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
J'ai modifié la ligne &amp;lt;code&amp;gt;int bitOffset = 7 - (blockNum % 8);&amp;lt;/code&amp;gt; pour inverser l'ordre des bits sélectionnés, de sorte que le bit correspondant au bloc disponible soit correct.&lt;br /&gt;
&lt;br /&gt;
ReX : Encore plus faux.&lt;br /&gt;
&lt;br /&gt;
Si on veut rendre le bloc 1030 indisponible alors que les autres blocs sont disponibles:&lt;br /&gt;
&lt;br /&gt;
ReX : Pardon ? Le bloc de données est libre ou pas suivant la carte des blocs libres. Le rendre disponible n'est possible que si un fichier le comportant est détruit.&lt;br /&gt;
&lt;br /&gt;
# Calcul de l'indice de l'octet et du bit offset correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;blockNum = 1030&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;byteIndex = 1030 / 8 = 128&amp;lt;/code&amp;gt;&lt;br /&gt;
#* &amp;lt;code&amp;gt;bitOffset = 7 - 1030 % 8 = 1&amp;lt;/code&amp;gt;  Cela signifie que le bit d'intérêt se trouve à la position 2 dans l'octet.&lt;br /&gt;
# Calcul du numéro du bloc du super bloc où se trouve l'octet de disponibilité correspondant :&lt;br /&gt;
#* &amp;lt;code&amp;gt;availabilityBlockNum = SUPERBLOCK_START_BLOCK + 128 = 1024 + 128 = 1152&amp;lt;/code&amp;gt;  Donc, nous devons accéder à l'octet 1152 pour mettre à jour la disponibilité du bloc 1030.&lt;br /&gt;
# Lecture de l'octet existant dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet dans le bloc 1152 avant la mise à jour : 11111111 (en binaire)&lt;br /&gt;
# Mise à jour du bit d'offset correspondant :&lt;br /&gt;
#* Supposons que nous voulions marquer le bloc 1030 comme non disponible (&amp;lt;code&amp;gt;availability = 0&amp;lt;/code&amp;gt;).&lt;br /&gt;
#* Le bitOffset est 1.&lt;br /&gt;
#* Nous effectuons une opération AND avec le complément du bit à la position 1 : &amp;lt;code&amp;gt;11111111 &amp;amp; 11111101 = 11111101&amp;lt;/code&amp;gt;&lt;br /&gt;
# Écriture de l'octet mis à jour dans le bloc de disponibilité du super bloc :&lt;br /&gt;
#* Le contenu de l'octet 128 du second superbloc après la mise à jour : 11111101 (en binaire)&lt;br /&gt;
&lt;br /&gt;
ReX : Toujours aussi faux.&lt;br /&gt;
&lt;br /&gt;
Maintenant, le bit d'indice 1 du 128 ème octet du second superbloc est mis à 0, indiquant que le bloc 1030 n'est plus disponible. Les autres bits restent inchangés car nous avons effectué un AND avec un masque binaire qui avait des 1 partout sauf à la position du bit que nous souhaitions mettre à 0.&lt;br /&gt;
&lt;br /&gt;
ReX : Erreur sur erreur.&lt;br /&gt;
&lt;br /&gt;
=== '''Fonction setBlockAvailability''' ===&lt;br /&gt;
J'ai compris d'où vient l'erreur. La fonction readBlock prends en premier paramètre le numéro du bloc à lire, je ne peux donc pas lui donner la valeur &amp;quot;SUPERBLOCK_START_BLOCK + byteIndex&amp;quot; car byteIndex s'exprime en octet alors qu'on s'attend à un nombre de bloc ici. Il faut donc divisé byteIndex par 256 pour être en unité &amp;quot;bloc&amp;quot;, et préciser le bit qu'on veut lire grâce à l'offset. &lt;br /&gt;
&lt;br /&gt;
Pour obtenir l'octet que l'on veut, il faut prendre le reste de la division de byteIndex par 256. On va ensuite stocker cet octet dans notre &amp;quot;buffer&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Pour savoir quel bit modifier dans ce &amp;quot;buffer&amp;quot;, on va prendre le reste de la division du bloc dont on veut mettre à jour la disponibilité par 8. On va ainsi pouvoir modifier ce bit grâce à l'algorithme, puis réécrire l'octet à son emplacement d'origine.&lt;br /&gt;
&lt;br /&gt;
Cette fonction gère la carte de disponibilités des blocs. Si un bloc est disponible, alors elle le  met un 0, si il est indisponible, elle met un 1.&lt;br /&gt;
 #define SUPERBLOCK_START_BLOCK 1024&lt;br /&gt;
 &lt;br /&gt;
 void setBlockAvailability(int blockNum, int availability) {&lt;br /&gt;
 &lt;br /&gt;
     int byteIndexInCard = blockNum / 8; //Numéro d'octet dans la carte des blocs libres&lt;br /&gt;
     int blockIndex = byteIndexInCard / 256; //Numéro du bloc dans la carte des blocs libres &lt;br /&gt;
     int byteIndexInBlock = byteIndexInCard % 256; //Numéro d'octet dans le bloc contenant le bit de disponibilité&lt;br /&gt;
     int bitOffset = blockNum % 8; //Numéro du bit dans l'octet n°byteIndexInBlock du bloc blockIndex&lt;br /&gt;
     &lt;br /&gt;
     //indice du bloc contenant le bit à mettre à jour dans le superbloc&lt;br /&gt;
     int availabilityBlockNum = SUPERBLOCK_START_BLOCK + blockIndex;&lt;br /&gt;
 &lt;br /&gt;
     // Lire l'octet existant dans le bloc de disponibilité du super bloc&lt;br /&gt;
     unsigned char buffer;&lt;br /&gt;
     readBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 &lt;br /&gt;
     // Mettre à jour le bit d'offset correspondant :&lt;br /&gt;
     if (availability) {&lt;br /&gt;
         buffer &amp;amp;= ~(1 &amp;lt;&amp;lt; bitOffset); // Mettre le bit à 0&lt;br /&gt;
     } else {&lt;br /&gt;
         buffer |= (1 &amp;lt;&amp;lt; bitOffset);  // Mettre le bit à 1&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Écrire l'octet mis à jour dans le bloc de disponibilité du super bloc&lt;br /&gt;
     writeBlock(availabilityBlockNum, byteIndexInBlock, &amp;amp;buffer, 1);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ben voila, c'est pas possible de te taxer d'excès de vitesse mais c'est bon.&lt;br /&gt;
&lt;br /&gt;
update: j'ai fait une petite modification, maintenant un bloc disponible est marqué d'un 0 et un bloc indisponible est marqué d'un 1. C'est mieux dans la mesure où initialement, tous les blocs sont disponibles et tous les blocs sont à 0. Cela évite de devoir créer une fonction qui initialise toute la carte de disponibilités à 1 pour dire que tous les blocs sont disponibles.&lt;br /&gt;
&lt;br /&gt;
'''fonction RM''':&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     int fileNum = -1;&lt;br /&gt;
 &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[MAX_BLOCKS_PER_FILE * 2];&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier et réinitialiser les numéros de blocs&lt;br /&gt;
             for (int i = 0; i &amp;lt; MAX_BLOCKS_PER_FILE * 2; i += 2) {&lt;br /&gt;
                 int blockNum = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNum, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             // Mettre à jour les numéros de blocs associés au fichier&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, MAX_BLOCKS_PER_FILE * 2);&lt;br /&gt;
 &lt;br /&gt;
             fileNum = blockNum;&lt;br /&gt;
             break; // Fichier trouvé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Afficher le résultat de l'opération&lt;br /&gt;
     if (fileNum == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Vous utilisez &amp;lt;code&amp;gt;strcmp&amp;lt;/code&amp;gt; comme &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt;. C'est bien la dernière qu'il faut utiliser mais en précisant la longueur du nom en paramètre, pas la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: vous voulez dire que j'utilise memcmp au lieu de strncmp ? Ok je vais utiliser strncmp, c'est vrai que c'est plus adapté pour la comparaison de chaines de caractère. &lt;br /&gt;
&lt;br /&gt;
ReX : Ha oui c'est &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt; que tu utilises. Ca ne peut effectivement pas marcher. Effectivement avec &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; cela peut marcher vu qu'il s'arrête au premier 0 contrairement à &amp;lt;code&amp;gt;memcmp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cependant, pourquoi doit-on passer la taille exacte du nom du fichier en paramètre, et non la taille maximale d'un nom de fichier? En effet, cela semble fonctionner en mettant la taille maximale en paramètre, tandis que lorsque l'on met la taille exacte du nom du fichier, cela pose un problème: on ne compare plus toute la chaîne de caractère mais seulement une portion du nom complet. Ainsi, si je crée par exemple un fichier que j'appelle &amp;quot;file1&amp;quot;, puis que j’exécute la fonction RM &amp;quot;/picofs filesystem.bin RM file&amp;quot; par exemple, alors le fichier file1 va être supprimé quand même car on ne comparera que strlen(file)=4 premiers caractères, qui sont les mêmes, donc la fonction considérera ces chaines comme identiques.  On pourrait alors se dire qu'il faudrait alors prendre plutôt comme taille en paramètre de la fonction strlen la taille du nom du fichier se trouvant dans le système de fichier plutôt que celle du nom donné en paramètre de RM. Cependant, le même problème se pose si la taille du nom du fichier du système de fichier est plus petite que celle du nom du fichier passé en paramètre. Par exemple, si le fichier présent dans système de fichier est &amp;quot;file&amp;quot;, et qu'on met la longueur de file en paramètre de la fonction strcmp, puis qu'on exécute la commande  &amp;quot;/picofs filesystem.bin RM file5&amp;quot;, alors file sera quand même supprimé, car on ne comparera que les strlen(file)=4 premiers caractère. Finalement, une solution serait de rajouter une condition qui vérifie que les deux chaînes sont de taille identiques pour pouvoir réaliser la comparaison sur la taille exacte du nom du fichier. Cependant, il me semble qu'en mettant MAX_FILENAME_LENGTH qui vaut 16 en paramètre, cela fonctionne directement. Vous pouvez tester cela en testant mon programme. &lt;br /&gt;
&lt;br /&gt;
ReX : Ok pour &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; avec la taille maximale d'un nom de fichier.  &lt;br /&gt;
&lt;br /&gt;
etape 1: créer un fichier :&lt;br /&gt;
 ./picofs filesystem.bin TYPE fichier.txt &lt;br /&gt;
&lt;br /&gt;
etape 2: verifier que le fichier a bien été créé : &lt;br /&gt;
 ./picofs filesystem.bin LS &lt;br /&gt;
&lt;br /&gt;
Le terminal renvoie bien &amp;quot;fichier.txt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
etape 3: essayer de supprimer le fichier en mettant une chaine troncature du nom du fichier créé :&lt;br /&gt;
 ./picofs filesystem.bin RM fich &lt;br /&gt;
&lt;br /&gt;
le terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fich&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;, le fichier n'a donc pas été supprimé .&lt;br /&gt;
&lt;br /&gt;
etape 4: essayer de supprimer le fichier en mettant un nom plus grand incluant &amp;quot;fichier.txt&amp;quot; :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txtt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txtt&amp;quot; n'a pas été trouvé.&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
etape 5: enfin, tester en mettant le nom exacte du fichier que l'on veut supprimer :&lt;br /&gt;
 ./picofs filesystem.bin RM fichier.txt &lt;br /&gt;
&lt;br /&gt;
terminal renvoi &amp;lt;&amp;lt;Le fichier &amp;quot;fichier.txt&amp;quot; a été supprimé avec succès.&amp;gt;&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Finalement, on voit que cela fonctionne avec la taille maximale mise en paramètre. On pourrait reprocher à cette méthode de comparer des caractères dans le vide, ce qui n'est pas optimal dans une optique d'économie de mémoire qui est la notre, mais la taille maximale d'un nom de fichier étant relativement faible (16 octets), on peut peut-être négliger cela au vu de l'économie d'une opération supplémentaire (comparaison de la taille des chaines de caractères).    &lt;br /&gt;
&lt;br /&gt;
ReX : Le parcours des blocs de données du fichier est atroce. Il faut parcourir les numéros de blocs dans le premier bloc du fichier derrière le nom du fichier puis il faut parcourir le 15 autres blocs.&lt;br /&gt;
&lt;br /&gt;
Amine: Ok, je vais corriger cela dans la version 2 de RM (voir semaine 5). &lt;br /&gt;
&lt;br /&gt;
Fonctionnement de la fonction RM:&lt;br /&gt;
&lt;br /&gt;
* Parcours des blocs réservés pour la description des fichiers (superbloc) à partir du bloc 0, en incrémentant de 16 à chaque itération pour accéder aux blocs de noms de fichiers.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Dans chaque bloc de noms de fichiers, la fonction compare le nom de fichier recherché avec les noms stockés dans les 16 octets de chaque bloc.&lt;br /&gt;
&lt;br /&gt;
ReX : Non la fonction ne fait pas ça par contre il faudrait, oui.&lt;br /&gt;
&lt;br /&gt;
Amine: Je pensais que c'était ce que je faisais avec &amp;quot;memcmp(filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0)&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
* Si le nom de fichier est trouvé, la fonction efface le nom du fichier dans le superbloc en remplaçant les 16 octets du bloc par des zéros.&lt;br /&gt;
&lt;br /&gt;
ReX : OK.&lt;br /&gt;
&lt;br /&gt;
* Ensuite, la fonction accède aux octets suivants du même bloc pour obtenir les numéros de blocs associés au fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : Non, la boucle sort largement du premier bloc.&lt;br /&gt;
&lt;br /&gt;
* Pour chaque paire de numéros de blocs (2 octets chacun), la fonction convertit les octets en un numéro de bloc. Si le numéro de bloc est nul, cela signifie la fin des blocs associés au fichier, sinon, la fonction marque ce bloc comme disponible en utilisant la fonction &amp;lt;code&amp;gt;setBlockAvailability&amp;lt;/code&amp;gt; et réinitialise les numéros de blocs dans le tableau à zéro.&lt;br /&gt;
* Les numéros de blocs réinitialisés sont ensuite réécrits dans le bloc de description du fichier.&lt;br /&gt;
&lt;br /&gt;
ReX : L'idée est là mais vu que la boucle n'est pas bonne, rien ne peut marcher.&lt;br /&gt;
&lt;br /&gt;
* La fonction affiche ensuite un message indiquant le résultat de l'opération : soit que le fichier a été supprimé avec succès, soit que le fichier n'a pas été trouvé.&lt;br /&gt;
&lt;br /&gt;
== Semaine 5 ==&lt;br /&gt;
'''Fonction RM version 2'''&lt;br /&gt;
&lt;br /&gt;
Concernant les remarques que vous m'avez faites précédemment:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant la fonction &amp;lt;code&amp;gt;strncmp&amp;lt;/code&amp;gt; pour la comparaison des chaines de caractères&lt;br /&gt;
* j'ai normalement corrigé le parcours des blocs. Je parcours maintenant d'abord les blocs multiples de 16 à la recherche du bloc contenant le nom du fichier à supprimer. Puis je parcours les 16 blocs de description du fichier à supprimer, afin de récupérer les numéros de blocs, libérer ces blocs dans la carte de disponibilité et de réinitialiser ces blocs dans les blocs de données.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
       //bloc que l'on va remplir de 0 et mettre à la place des blocs de données&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE); //on rempli buffer de 0&lt;br /&gt;
     &lt;br /&gt;
     for (int blockNum=offset; blockNum&amp;lt;offset + 16; blockNum++) {&lt;br /&gt;
         &lt;br /&gt;
         //premier bloc de description, celui contenant le nom du fichier dans les 16 premiers octets&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
 &lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE-MAX_FILENAME_LENGTH];&lt;br /&gt;
               //bloc dans lequel on va stocker les blocs de description de fichier&lt;br /&gt;
             readBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 &lt;br /&gt;
 &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités&lt;br /&gt;
             //  et dans les blocs de description&lt;br /&gt;
             for (int i = MAX_FILENAME_LENGTH; i &amp;lt; BLOCK_SIZE-MAX_FILENAME_LENGTH; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, MAX_FILENAME_LENGTH, fileBuffer, BLOCK_SIZE-MAX_FILENAME_LENGTH);&lt;br /&gt;
                 //on efface le premier bloc de description&lt;br /&gt;
             &lt;br /&gt;
         } else {&lt;br /&gt;
             unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
             readBlock(blockNum, 0, fileBuffer, BLOCK_SIZE);&lt;br /&gt;
             &lt;br /&gt;
             // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
             for (int i = 0; i &amp;lt; BLOCK_SIZE; i += 2) {&lt;br /&gt;
                 int blockNumData = ((int)fileBuffer[i] &amp;lt;&amp;lt; 8) + (int)fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
                 writeBlock(blockNumData, 0, buffer, BLOCK_SIZE); //on efface les blocs de données&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, fileBuffer, BLOCK_SIZE); //on efface le bloc de description&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Pour construire le nombre sur 16 bits utiliser le OU plutôt que l'addition.&lt;br /&gt;
&lt;br /&gt;
ReX : Heu non, je ne lis pas cette fonction avec tout ce code dupliqué, la seule différence entre les deux alternative est la position de début de l'adresse du premier bloc de données (&amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt; dans un cas et 0 dans l'autre). Donc l'alternative ne doit servir qu'à initialiser ce début, le reste du code doit être factorisé.&lt;br /&gt;
&lt;br /&gt;
ReX : Et corrige le code, tu utilises deux tableaux de blocs (perte mémoire), tu écris le bloc à zéro dans l'itération (perte CPU).&lt;br /&gt;
&lt;br /&gt;
'''Fonction RM version 3'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai réalisé les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* j'utilise maintenant le OU plutôt que l'addition pour construire le nombre sur 16 bits.&lt;br /&gt;
&lt;br /&gt;
* j'ai factorisé le code grâce à la création de la variable &amp;lt;code&amp;gt;startOffset&amp;lt;/code&amp;gt; valant 16 lorsqu'on se trouve dans le bloc contenant le nom du fichier et valant 0 lorsqu'on se trouve dans les autres. &lt;br /&gt;
&lt;br /&gt;
* Pour ce qui est du fait que j'utilise 2 tableaux de blocs, j'ai du mal à voir comment faire avec 1 seul tableau de blocs car ces deux tableaux n'ont pas du tout le même rôle. Le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; permet de stocker les 16 blocs de description d'un fichier un à un. Lorsqu'on stocke un bloc dans &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;, on lit ensuite les octets un à un de ce bloc afin de former des numéros de blocs, et pour chaque numéro de bloc créé, on va réinitialiser le bloc correspondant dans les blocs de données. Pour cela, on a donc besoin d'un autre bloc qui viendra écraser les anciens blocs de données. C'est pourquoi j'ai créé un bloc &amp;lt;code&amp;gt;buffer&amp;lt;/code&amp;gt;qui est composé de 0 et qui va écraser les blocs de données. On ne peut pas utiliser &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; car on a besoin d'un bloc de zéros, et si on réinitialise &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt; on perd toute les données qui s'y trouvent. Une possibilité serait de relire le bloc de donné à chaque itération de la deuxième boucle for imbriquée; cela permettrait de pouvoir réinitialiser le tableau fileBuffer à chaque itérations de cette boucle afin de stocker ce bloc de 0 dans les blocs de données, puis de restocker dans ce même tableau le bloc de description. Cependant, je ne pense pas que ce soit optimal de faire autant appel à la fonction readBlock. &lt;br /&gt;
&lt;br /&gt;
* j'ai créé une fonction resetBock qui permet comme son nom l'indique de reset un bloc en le remplissant de 0. Cela nous évite de créer deux tableaux de blocs dans RM, bien que je pense que cela revienne au même car on fait appel à une fonction qui créé un tableau de blocs. Quoi qu'il en soit, cela allège le code et cette fonction pourra surement me resservir par la suite.&lt;br /&gt;
&lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {         &lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
         readBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
 &lt;br /&gt;
         // Libérer les blocs associés au fichier dans la carte de disponibilités et dans les blocs de description&lt;br /&gt;
         for (int i = 0; i &amp;lt; BLOCK_SIZE - startOffset; i += 2) {&lt;br /&gt;
             int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
             if (blockNumData == 0) {&lt;br /&gt;
                 break; // Fin du fichier&lt;br /&gt;
             }&lt;br /&gt;
             setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
             fileBuffer[i] = 0;&lt;br /&gt;
             fileBuffer[i + 1] = 0;&lt;br /&gt;
             resetBlock(blockNumData); //on efface les blocs de données&lt;br /&gt;
         }&lt;br /&gt;
         writeBlock(blockNum, startOffset, fileBuffer, BLOCK_SIZE - startOffset);&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
'''Fonction resetBlock'''&lt;br /&gt;
 void resetBlock(unsigned int blockNum) {&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     memset(buffer, 0, BLOCK_SIZE);&lt;br /&gt;
 &lt;br /&gt;
     // Utiliser writeBlock pour écrire les données du buffer dans le bloc&lt;br /&gt;
     writeBlock(blockNum, 0, buffer, BLOCK_SIZE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Ca s'améliore. Mais pourquoi cette fonction &amp;lt;code&amp;gt;resetBlock&amp;lt;/code&amp;gt; ? Tu crois que dans qu'un système de fichiers perd du temps à mettre à zéro les blocs de données libérés ? Si oui, regarde la page de manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, ça manque à ta culture.&lt;br /&gt;
&lt;br /&gt;
Amine: Après avoir consulter le manual de la commande &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;, je vois que cette commande écrit des données aléatoires sur l'emplacement du fichier sur le disque. Par défaut, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; effectue un certain nombre de passes (par exemple, 3 passes) pendant lesquelles il écrit des données aléatoires sur l'emplacement du fichier sur le disque. Après avoir écrit les données aléatoires, &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; peut effectuer des passes supplémentaires pendant lesquelles il écrit des données nulles (des zéros) sur le même emplacement. L'objectif de &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt; est d'augmenter la sécurité en rendant plus difficile la récupération des données supprimées à l'aide d'outils de récupération de données. &lt;br /&gt;
&lt;br /&gt;
Cependant, j'ai aussi consulté comment fonctionne la commande &amp;lt;code&amp;gt;rm&amp;lt;/code&amp;gt; de linux, et je vois que cette commande libère l'espace occupé par le fichier en marquant les blocs associés comme disponibles. Cela signifie que les données peuvent encore être récupérées à l'aide d'outils de récupération de données, à moins que des mesures supplémentaires ne soient prises pour écraser physiquement l'espace avec des données aléatoires (c'est ce que fait l'utilitaire &amp;lt;code&amp;gt;shred&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
On va donc opter pour la deuxième option, c'est à dire qu'on ne va pas perdre notre temps à remettre à zéro les blocs de données libérés, on va simplement marquer les blocs correspondants comme étant disponibles. Cela nous permettra de nous émanciper de la fonction resetBlock et de n'avoir plus qu'un seul tableau de blocs. &lt;br /&gt;
&lt;br /&gt;
ReX : Sinon lire un bloc complet de pointeurs de blocs de données en mémoire n'est pas forcément optimal. L'idéal serait de lire ces blocs morceau par morceau (de 64 octets par exemple). Certes un bloc serait traité en 4 lectures/écritures (ce qui ralentirait le traitement) mais on gagne en mémoire. Le mieux serait de mettre la taille des morceaux en constante pour pouvoir choisir entre vitesse d'exécution et utilisation mémoire.&lt;br /&gt;
&lt;br /&gt;
Amine: d'accord je comprends. Je vais modifier la fonction pour qu'on puisse découper la lecture/écriture en plusieurs blocs. &lt;br /&gt;
&lt;br /&gt;
=== Fonction RM version 4 ===&lt;br /&gt;
Modifications apportées:&lt;br /&gt;
&lt;br /&gt;
* je ne réinitialise plus les blocs de données, je supprime simplement le pointeur du fichier vers les blocs de données et je désigne les blocs comme &amp;quot;disponible&amp;quot; dans le carte de disponibilités. J'ai donc supprimé la fonction resetBlock.&lt;br /&gt;
&lt;br /&gt;
* je ne lis plus les blocs en une seule fois mais en plusieurs fois via la variable CHUNK_SIZE:&lt;br /&gt;
&lt;br /&gt;
# J'ai introduit la constante &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; pour définir la taille de chaque morceau que nous allons lire/écrire à la fois. Cela permet de découper les opérations en blocs plus petits.&lt;br /&gt;
# Dans la boucle &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; où on parcours les blocs à partir de &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt;, j'ai ajouté une boucle interne qui parcourt les données du bloc en morceaux de taille &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
# À l'intérieur de la boucle interne, j'ai calculé la taille réelle du morceau (&amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt;) en prenant le minimum entre &amp;lt;code&amp;gt;CHUNK_SIZE&amp;lt;/code&amp;gt; et la quantité de données restant à lire/écrire dans le bloc.&lt;br /&gt;
# J'ai modifié la fonction &amp;lt;code&amp;gt;readBlock&amp;lt;/code&amp;gt; pour lire seulement la quantité de données spécifiée par &amp;lt;code&amp;gt;chunkSize&amp;lt;/code&amp;gt; à partir de &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt;. Ces données sont stockées dans le tableau &amp;lt;code&amp;gt;fileBuffer&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ensuite, j'ai effectué les mêmes opérations de libération des blocs associés au fichier, en parcourant les données du morceau et en marquant les blocs comme disponibles.&lt;br /&gt;
# Finalement, j'ai utilisé la fonction &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; pour écrire le morceau de données modifié dans le bloc, en utilisant la même &amp;lt;code&amp;gt;chunkStart&amp;lt;/code&amp;gt; pour déterminer où écrire les données.&lt;br /&gt;
&lt;br /&gt;
 #define CHUNK_SIZE 64&lt;br /&gt;
 &lt;br /&gt;
 int min(int a, int b) {&lt;br /&gt;
     return a &amp;lt; b ? a : b;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void RM(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     int fileFound = -1;&lt;br /&gt;
     int offset;&lt;br /&gt;
     unsigned char fileBuffer[BLOCK_SIZE];&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
 &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             fileFound = 1;&lt;br /&gt;
             offset = blockNum;&lt;br /&gt;
             break;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Fin de fonction si fichier inexistant&lt;br /&gt;
     if (fileFound == -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int blockNum = offset; blockNum &amp;lt; offset + 16; blockNum++) {&lt;br /&gt;
         int startOffset = 0;&lt;br /&gt;
 &lt;br /&gt;
         if (blockNum == offset) {&lt;br /&gt;
             startOffset = MAX_FILENAME_LENGTH;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         for (int chunkStart = startOffset; chunkStart &amp;lt; BLOCK_SIZE; chunkStart += CHUNK_SIZE) {&lt;br /&gt;
             int chunkSize = min(CHUNK_SIZE, BLOCK_SIZE - chunkStart);&lt;br /&gt;
             readBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
 &lt;br /&gt;
             for (int i = 0; i &amp;lt; chunkSize; i += 2) {&lt;br /&gt;
                 int blockNumData = (fileBuffer[i] &amp;lt;&amp;lt; 8) | fileBuffer[i + 1];&lt;br /&gt;
                 if (blockNumData == 0) {&lt;br /&gt;
                     writeBlock(blockNum, chunkStart, fileBuffer, chunkSize); &lt;br /&gt;
                     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
                     return; // Sortir des boucles&lt;br /&gt;
                 }&lt;br /&gt;
                 setBlockAvailability(blockNumData, 0); // Marquer le bloc comme disponible&lt;br /&gt;
                 fileBuffer[i] = 0;&lt;br /&gt;
                 fileBuffer[i + 1] = 0;&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             writeBlock(blockNum, chunkStart, fileBuffer, chunkSize);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été supprimé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si on trouve un n° de bloc de données à 0, il faut sortir des deux boucles les plus externes après avoir fait le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Amine: Modification faites ci-dessus. Maintenant, dès qu'on trouve un n° de bloc de données à 0 dans la boucle la plus interne, on effectue le &amp;lt;code&amp;gt;writeBlock&amp;lt;/code&amp;gt; et ensuite on utilise &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; pour sortir des deux boucles les plus externes. Cela permet d'optimiser le code en évitant de continuer à traiter inutilement le reste des blocs.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE:''' &lt;br /&gt;
&lt;br /&gt;
J'ai également commencé à réfléchir à la fonction TYPE. Pour l'instant, elle ne fait qu'ajouter les noms de fichier dans le superbloc. Cela permet de pouvoir tester les fonctions LS et RM (voir dans la rubrique compilation et exécution comment utiliser le programme). &lt;br /&gt;
 // Fonction pour créer un fichier avec le nom donné et le contenu fourni en entrée standard&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, MAX_FILENAME_LENGTH); &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Si la boucle se termine sans trouver de slot libre le message de succès s'affiche tout de même.&lt;br /&gt;
&lt;br /&gt;
ReX : Le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'a pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Selon moi, la fonction TYPE devra respecter 3 étapes:&lt;br /&gt;
&lt;br /&gt;
# Enregistrement du Nom du Fichier: L'ajout du nom du fichier dans un des blocs de la première partie du superbloc.&lt;br /&gt;
# Stockage des Données du Fichier: La récupération des données saisies en entrée standard par l'utilisateur et leur stockage dans des blocs du système de fichiers à partir d'une certaine position, comme le bloc 1040.&lt;br /&gt;
# Mise à Jour de la Disponibilité des Blocs: L'indication que les blocs dans lesquels les données ont été écrites ne sont plus disponibles en modifiant les bits correspondants dans la deuxième partie du superbloc (les 16 derniers blocs du super bloc).&lt;br /&gt;
&lt;br /&gt;
ReX : Relis le point 3 et dit moi si tu te comprends toi même ?&lt;br /&gt;
&lt;br /&gt;
Amine: Ma phrase n'est effectivement pas très claire. Je voulais dire que la fonction TYPE devra mettre à jour la carte de disponibilité du superbloc. C'est à dire que lorsqu'elle écrira des données dans des blocs, elle devra indiquer dans la carte de disponibilités que ces blocs ne sont plus disponibles.&lt;br /&gt;
&lt;br /&gt;
'''Fonction intermédiaire TYPE version 2'''&lt;br /&gt;
&lt;br /&gt;
Suite à vos remarques, j'ai apporté les modifications suivantes à la fonction TYPE: &lt;br /&gt;
&lt;br /&gt;
* j'ai ajouté une condition pour l'affichage du message de succès de la création d'un fichier (placeFound).&lt;br /&gt;
&lt;br /&gt;
* le paramètre &amp;lt;code&amp;gt;filename&amp;lt;/code&amp;gt; n'ayant pas forcément une taille de &amp;lt;code&amp;gt;MAX_FILENAME_LENGTH&amp;lt;/code&amp;gt;, je calcule maintenant la longueur de filename, afin d'écrire seulement le nom du fichier avec la fonction writeBlock.&lt;br /&gt;
&lt;br /&gt;
Il fonction n'est bien évidemment pas fini, elle ajoute seulement le nom du fichier dans le superbloc pour l'instant. Cela me permet de tester les fonctions LS et RM. &lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     printf(&amp;quot;size filename=%d\n&amp;quot;, sizeFilename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = 1;&lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (placeFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;, filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Mieux, attention il faut copier aussi le &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; final du nom, donc &amp;lt;code&amp;gt;sizeFilename+1&amp;lt;/code&amp;gt;. Sinon tu n'es pas sûr qu'il y ait un zéro final. Et attention n°2, il ne faut pas copier ce &amp;lt;code&amp;gt;\'0&amp;lt;/code&amp;gt; si le nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok j'ai modifié la fonction TYPE ci-dessus. J'ai ajouté une condition: si le nom du fichier est inférieur à la taille maximale de nom de fichier, alors on incrémente de 1 la taille du nom de fichier. Cela nous permet d'écrire le '\0' dans le bloc de description. Dans le cas où le nom du fichier est de la taille maximale, nous n'avons pas besoin d'écrire le '\0', on n'incrémente donc pas la taille de 1. &lt;br /&gt;
&lt;br /&gt;
J'ai également ajouté une condition: si le nom du fichier est supérieur à la taille maximale, alors un message d'erreur s'affiche et le fichier n'est pas créé. &lt;br /&gt;
&lt;br /&gt;
'''Fonction MV version 1'''&lt;br /&gt;
&lt;br /&gt;
J'ai ici créé la fonction MV qui permet de changer le nom d'un fichier. Pour se faire, la fonction parcours les blocs de descriptions à la recherche du fichier dont on veut changer le nom. Lorsque ce fichier est trouvé, on supprime l'ancien nom en mettant des 0 sur 16 octets, puis on vient réécrire le nouveau nom dans le même emplacement. Enfin, on sort de la boucle et on affiche le succès ou non de l'opération. &lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Effacer le nom du fichier dans le superbloc&lt;br /&gt;
             memset(filenameBuffer, 0, MAX_FILENAME_LENGTH);&lt;br /&gt;
             writeBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             fileFound=1;&lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
ReX : Inutile d'écraser l'ancien nom avec des zéros. Il suffit de copier le nouveau en s'assurant qu'il y ait un zéro final sauf si le nouveau nom fait la taille maximale.&lt;br /&gt;
&lt;br /&gt;
Amine: ok, je vais modifications dans la version 2.&lt;br /&gt;
&lt;br /&gt;
== Semaine 6 ==&lt;br /&gt;
&lt;br /&gt;
=== Fonction MV version 2 ===&lt;br /&gt;
Dans cette nouvelle version de la fonction MV, j'ai effectué les modifications suivantes:&lt;br /&gt;
&lt;br /&gt;
* je n'écrase plus l'ancien nom avec des 0&lt;br /&gt;
* Je colle simplement le nouveau nom par dessus l'ancien, en m'assurant qu'il y ait bien le '\0' à la fin lorsque la taille du nom du fichier est inférieur à la taille maximale. Comme précédemment, afin de m'assurer de la présence de ce '\0' à la fin du nom, j'incrémente la taille de 1 lorsque qu'elle est inférieur à la taille max. Cependant, je ne suis pas sûr à 100% que ce soit la bonne manière de faire. &lt;br /&gt;
&lt;br /&gt;
 // Fonction qui modifie le nom du fichier&lt;br /&gt;
 void MV(const char *filesystem_path, const char *old_filename, const char *new_filename) {&lt;br /&gt;
     size_t sizeNew_filename = strlen(new_filename);&lt;br /&gt;
     size_t sizeOld_filename = strlen(old_filename);&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int fileFound = 0;&lt;br /&gt;
     &lt;br /&gt;
     // Parcourir les blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         &lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char*)filenameBuffer, old_filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             &lt;br /&gt;
             if (sizeNew_filename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeNew_filename+=1;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)new_filename, sizeNew_filename);&lt;br /&gt;
             &lt;br /&gt;
             fileFound=1;&lt;br /&gt;
 &lt;br /&gt;
             break; // Nom modifié, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     if (fileFound == 1) {&lt;br /&gt;
         printf(&amp;quot;Le nom du fichier \&amp;quot;%s\&amp;quot; a été renommé avec succès.\n&amp;quot;, old_filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, old_filename);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction TYPE version 1 ===&lt;br /&gt;
 void TYPE(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     size_t sizeFilename = strlen(filename);&lt;br /&gt;
     unsigned char buffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     int placeFound = -1;&lt;br /&gt;
     &lt;br /&gt;
     if (sizeFilename &amp;gt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
         printf(&amp;quot;Impossible de créer le fichier, nom trop long\n&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, buffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         // Vérifier si le bloc est vide (pas de nom de fichier)&lt;br /&gt;
         if (buffer[0] == 0) {&lt;br /&gt;
             // Écrire le nom du fichier dans l'emplacement vide du superbloc&lt;br /&gt;
             if (sizeFilename &amp;lt; MAX_FILENAME_LENGTH) {&lt;br /&gt;
                 sizeFilename += 1; // Ajouter '\0' s'il y a de la place&lt;br /&gt;
             }&lt;br /&gt;
             writeBlock(blockNum, 0, (const unsigned char *)filename, sizeFilename);&lt;br /&gt;
             placeFound = blockNum;&lt;br /&gt;
             &lt;br /&gt;
             // Lire les données depuis l'entrée standard&lt;br /&gt;
             unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
             size_t bytesRead;&lt;br /&gt;
             int dataBlockNum = findAvailableBlock(); // Premier bloc de données à partir du bloc 1040&lt;br /&gt;
             printf(&amp;quot;dataBlockNum%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
             int blockSizeUsed = 0; // Compteur d'octets dans le bloc actuel&lt;br /&gt;
             int dataBlocksNeeded = 1; // Nombre de blocs de données nécessaires&lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
             &lt;br /&gt;
             while ((bytesRead = fread(dataBuffer + blockSizeUsed, 1, BLOCK_SIZE - blockSizeUsed, stdin)) &amp;gt; 0) {&lt;br /&gt;
                 blockSizeUsed += bytesRead;&lt;br /&gt;
                 &lt;br /&gt;
                 // Si le bloc actuel est plein, passer au bloc suivant&lt;br /&gt;
                 if (blockSizeUsed == BLOCK_SIZE) {&lt;br /&gt;
                     // printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                     writeBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                     setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
                     &lt;br /&gt;
                     dataBlockNum++; // Passer au bloc suivant&lt;br /&gt;
                     blockSizeUsed = 0; // Réinitialiser la taille utilisée&lt;br /&gt;
                     dataBlocksNeeded++;&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire le dernier bloc partiel, s'il y en a un&lt;br /&gt;
             if (blockSizeUsed &amp;gt; 0) {&lt;br /&gt;
                 writeBlock(dataBlockNum, 0, dataBuffer, blockSizeUsed);&lt;br /&gt;
                 setBlockAvailability(dataBlockNum, 1);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             // Écrire les numéros de blocs utilisés dans le bloc de description&lt;br /&gt;
             unsigned char blockNumberBuffer[2];&lt;br /&gt;
             int currentBlockNum = 1040;&lt;br /&gt;
             &lt;br /&gt;
             for (int i = 0; i &amp;lt; dataBlocksNeeded; i++) {&lt;br /&gt;
                 blockNumberBuffer[0] = (currentBlockNum &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;
                 blockNumberBuffer[1] = currentBlockNum &amp;amp; 0xFF;&lt;br /&gt;
                 writeBlock(placeFound, MAX_FILENAME_LENGTH + i * 2, blockNumberBuffer, 2);&lt;br /&gt;
                 currentBlockNum++;&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             break; // Fichier créé, sortir de la boucle&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     if (placeFound != -1) {&lt;br /&gt;
         printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; a été créé avec succès.\n&amp;quot;, filename);&lt;br /&gt;
     } else {&lt;br /&gt;
         printf(&amp;quot;Plus de place dans le système de fichier pour créer ce fichier.\n&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
Dans cette nouvelle version de TYPE, j'ai ajouté un système de lecture des données entrées en entrée standard, d'écriture de ces données dans les blocs de données et de mise à jour des blocs utilisés dans les blocs de disponibilité. &lt;br /&gt;
&lt;br /&gt;
=== Fonction findAvailableBlock ===&lt;br /&gt;
Cette fonction renvoie le numéro du premier bloc disponible. Je l'utilise dans la fonction TYPE. &lt;br /&gt;
 int findAvailableBlock() {&lt;br /&gt;
     unsigned char availabilityBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
 &lt;br /&gt;
     // Lire la carte de disponibilité (à partir du bloc 1)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt;= 16; blockNum++) {&lt;br /&gt;
         readBlock(blockNum, 0, availabilityBuffer, BLOCK_SIZE);&lt;br /&gt;
         &lt;br /&gt;
         if (blockNum==0) {&lt;br /&gt;
             offset=1040;&lt;br /&gt;
         } else {&lt;br /&gt;
             offset=0;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // Parcourir les octets de la carte de disponibilité&lt;br /&gt;
         for (int byteIndex = offset; byteIndex &amp;lt; BLOCK_SIZE-offset; byteIndex++) {&lt;br /&gt;
             unsigned char byte = availabilityBuffer[byteIndex];&lt;br /&gt;
             &lt;br /&gt;
             // Parcourir les bits de chaque octet&lt;br /&gt;
             for (int bitIndex = 0; bitIndex &amp;lt; 8; bitIndex++) {&lt;br /&gt;
                 // Vérifier si le bit est à 0 (bloc disponible)&lt;br /&gt;
                 if ((byte &amp;amp; (1 &amp;lt;&amp;lt; bitIndex)) == 0) {&lt;br /&gt;
                     // Calculer l'indice du bloc en fonction du bloc et du bit&lt;br /&gt;
                     int blockIndex = (blockNum - 1) * 8 + byteIndex * 8 + bitIndex;&lt;br /&gt;
                     return 1040 + blockIndex; // Ajouter 1041 pour obtenir l'indice réel du bloc&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     // Aucun bloc disponible trouvé&lt;br /&gt;
     return -1;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Fonction CAT ===&lt;br /&gt;
 void CAT(const char *filesystem_path, const char *filename) {&lt;br /&gt;
     unsigned char filenameBuffer[MAX_FILENAME_LENGTH];&lt;br /&gt;
     unsigned char buffer[BLOCK_SIZE];&lt;br /&gt;
     unsigned char blockNumberBuffer[2];&lt;br /&gt;
     unsigned char dataBuffer[BLOCK_SIZE];&lt;br /&gt;
     int offset;&lt;br /&gt;
     &lt;br /&gt;
     // Parcours des blocs réservés pour la description des fichiers (superbloc)&lt;br /&gt;
     for (int blockNum = 0; blockNum &amp;lt; MAX_FILES_IN_DIRECTORY; blockNum += 16) {&lt;br /&gt;
         readBlock(blockNum, 0, filenameBuffer, MAX_FILENAME_LENGTH);&lt;br /&gt;
         &lt;br /&gt;
         // Vérifier si le bloc contient le nom du fichier recherché&lt;br /&gt;
         if (strncmp((const char *)filenameBuffer, filename, MAX_FILENAME_LENGTH) == 0) {&lt;br /&gt;
             // Le nom du fichier a été trouvé&lt;br /&gt;
             &lt;br /&gt;
             // Parcours les blocs de description&lt;br /&gt;
             for (int descrBlockNum=0; descrBlockNum&amp;lt;MAX_BLOCKS_PER_FILE_DESCRIPTION; descrBlockNum++) {&lt;br /&gt;
                 if (descrBlockNum==0) {&lt;br /&gt;
                     offset=16;&lt;br /&gt;
                 } else {&lt;br /&gt;
                     offset=0;&lt;br /&gt;
                 }&lt;br /&gt;
                 readBlock(descrBlockNum+blockNum, offset, buffer, BLOCK_SIZE);&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire les numéros de blocs associés à ce fichier depuis les blocs de description&lt;br /&gt;
                 unsigned char octet1 = buffer[offset];&lt;br /&gt;
                 unsigned char octet2 = buffer[offset+1];&lt;br /&gt;
                 &lt;br /&gt;
                 int dataBlockNum = (octet1 &amp;lt;&amp;lt; 8) | octet2;&lt;br /&gt;
                 printf(&amp;quot;dataBlockNum=%d\n&amp;quot;,dataBlockNum);&lt;br /&gt;
                 &lt;br /&gt;
                 // Vérifier si le numéro de bloc est valide (non nul)&lt;br /&gt;
                 if (dataBlockNum == 0) {&lt;br /&gt;
                     break; // Fin du fichier&lt;br /&gt;
                 }&lt;br /&gt;
                 &lt;br /&gt;
                 // Lire et afficher le contenu du bloc de données&lt;br /&gt;
                 readBlock(dataBlockNum, 0, dataBuffer, BLOCK_SIZE);&lt;br /&gt;
                 fwrite(dataBuffer, 1, BLOCK_SIZE, stdout);&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             return; // Fichier affiché, sortie de la fonction&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     // Si le fichier n'a pas été trouvé&lt;br /&gt;
     printf(&amp;quot;Le fichier \&amp;quot;%s\&amp;quot; n'a pas été trouvé.\n&amp;quot;, filename);&lt;br /&gt;
 }&lt;br /&gt;
Voici ma fonction &amp;lt;code&amp;gt;CAT&amp;lt;/code&amp;gt;. Elle fonctionne en plusieurs étape:&lt;br /&gt;
&lt;br /&gt;
* étape 1: on cherche dans les blocs de descriptions si le fichier dont on veut afficher le contenu existe. Si le nom de fichier est trouvé, on passe à l'étape 2. Sinon, on renvoie un message d'erreur.&lt;br /&gt;
* étape 2: si le fichier est trouvé, on parcours les 16 blocs de description de ce fichier.&lt;br /&gt;
* étape 3: grâce aux opérations de masquage et de décalage, on joint les octets deux par deux pour former un entier qui contient le numéro du bloc de donné correspondant au fichier. Si cet entier vaut 0, alors cela signifie qu'il n'y a plus de blocs associé à ce fichier, on peut donc quitter la fonction. Si cet entier est différent de 0, alors on va lire le bloc correspondant à ce numéro et on affiche son contenu dans le terminal.&lt;br /&gt;
&lt;br /&gt;
= Compilation et exécution =&lt;br /&gt;
'''Création du système de fichiers :'''&lt;br /&gt;
 dd if=/dev/zero of=filesystem.bin bs=256 count=32768&lt;br /&gt;
&lt;br /&gt;
'''Compilation :'''&lt;br /&gt;
&lt;br /&gt;
 gcc picofs.c -o picofs&lt;br /&gt;
&lt;br /&gt;
'''Exécution de LS, TYPE, CAT, RM, MV ou CP :'''&lt;br /&gt;
&lt;br /&gt;
 ./picofs filesystem.bin LS&lt;br /&gt;
 ./picofs filesystem.bin TYPE mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin CAT mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin RM mon_fichier.txt&lt;br /&gt;
 ./picofs filesystem.bin MV mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
 ./picofs filesystem.bin CP mon_fichier.txt mon_fichier2.txt&lt;br /&gt;
&lt;br /&gt;
= Documents Rendus =&lt;br /&gt;
[[Fichier:Picofs.c.tar|vignette]]&lt;/div&gt;</summary>
		<author><name>Asellali</name></author>
	</entry>
</feed>