Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
88ec37b6d43cc98e7e637079eaa38d8d84b24baa
[simgrid.git] / src / plugins / file_system / s4u_FileSystem.cpp
1 /* Copyright (c) 2015-2019. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "simgrid/plugins/file_system.h"
7 #include "simgrid/s4u/Actor.hpp"
8 #include "simgrid/s4u/Engine.hpp"
9 #include "src/surf/HostImpl.hpp"
10 #include "src/surf/xml/platf_private.hpp"
11 #include "xbt/config.hpp"
12
13 #include <algorithm>
14 #include <boost/algorithm/string.hpp>
15 #include <boost/algorithm/string/join.hpp>
16 #include <boost/algorithm/string/split.hpp>
17 #include <fstream>
18 #include <numeric>
19
20 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(s4u_file, s4u, "S4U files");
21 int sg_storage_max_file_descriptors = 1024;
22
23 namespace simgrid {
24 namespace s4u {
25 simgrid::xbt::Extension<Disk, FileSystemDiskExt> FileSystemDiskExt::EXTENSION_ID;
26 simgrid::xbt::Extension<Storage, FileSystemStorageExt> FileSystemStorageExt::EXTENSION_ID;
27 simgrid::xbt::Extension<Host, FileDescriptorHostExt> FileDescriptorHostExt::EXTENSION_ID;
28
29 Storage* File::find_local_storage_on(Host* host)
30 {
31   Storage* st                  = nullptr;
32   size_t longest_prefix_length = 0;
33   XBT_DEBUG("Search for storage name for '%s' on '%s'", fullpath_.c_str(), host->get_cname());
34
35   for (auto const& mnt : host->get_mounted_storages()) {
36     XBT_DEBUG("See '%s'", mnt.first.c_str());
37     mount_point_ = fullpath_.substr(0, mnt.first.length());
38
39     if (mount_point_ == mnt.first && mnt.first.length() > longest_prefix_length) {
40       /* The current mount name is found in the full path and is bigger than the previous*/
41       longest_prefix_length = mnt.first.length();
42       st                    = mnt.second;
43     }
44   }
45   if (longest_prefix_length > 0) { /* Mount point found, split fullpath_ into mount_name and path+filename*/
46     mount_point_ = fullpath_.substr(0, longest_prefix_length);
47     path_        = fullpath_.substr(longest_prefix_length, fullpath_.length());
48   } else
49     xbt_die("Can't find mount point for '%s' on '%s'", fullpath_.c_str(), host->get_cname());
50
51   return st;
52 }
53
54 Disk* File::find_local_disk_on(Host* host)
55 {
56   Disk* d                      = nullptr;
57   size_t longest_prefix_length = 0;
58   for (auto const& disk : host->get_disks()) {
59     std::string current_mount;
60     if (disk->get_host() != host)
61       current_mount = disk->extension<FileSystemDiskExt>()->get_mount_point(disk->get_host());
62     else
63       current_mount = disk->extension<FileSystemDiskExt>()->get_mount_point();
64     mount_point_ = fullpath_.substr(0, current_mount.length());
65     if (mount_point_ == current_mount && current_mount.length() > longest_prefix_length) {
66       /* The current mount name is found in the full path and is bigger than the previous*/
67       longest_prefix_length = current_mount.length();
68       d                     = disk;
69     }
70     if (longest_prefix_length > 0) { /* Mount point found, split fullpath_ into mount_name and path+filename*/
71       mount_point_ = fullpath_.substr(0, longest_prefix_length);
72       if (mount_point_ == std::string("/"))
73         path_ = fullpath_;
74       else
75         path_ = fullpath_.substr(longest_prefix_length, fullpath_.length());
76       XBT_DEBUG("%s + %s", mount_point_.c_str(), path_.c_str());
77     } else
78       xbt_die("Can't find mount point for '%s' on '%s'", fullpath_.c_str(), host->get_cname());
79   }
80   return d;
81 }
82
83 File::File(const std::string& fullpath, void* userdata) : File(fullpath, Host::current(), userdata) {}
84
85 File::File(const std::string& fullpath, sg_host_t host, void* userdata) : fullpath_(fullpath)
86 {
87   this->set_data(userdata);
88   // this cannot fail because we get a xbt_die if the mountpoint does not exist
89   if (not host->get_mounted_storages().empty()) {
90     local_storage_ = find_local_storage_on(host);
91   }
92   if (not host->get_disks().empty()) {
93     local_disk_ = find_local_disk_on(host);
94   }
95
96   // assign a file descriptor id to the newly opened File
97   FileDescriptorHostExt* ext = host->extension<simgrid::s4u::FileDescriptorHostExt>();
98   if (ext->file_descriptor_table == nullptr) {
99     ext->file_descriptor_table.reset(new std::vector<int>(sg_storage_max_file_descriptors));
100     std::iota(ext->file_descriptor_table->rbegin(), ext->file_descriptor_table->rend(), 0); // Fill with ..., 1, 0.
101   }
102   xbt_assert(not ext->file_descriptor_table->empty(), "Too much files are opened! Some have to be closed.");
103   desc_id = ext->file_descriptor_table->back();
104   ext->file_descriptor_table->pop_back();
105
106   XBT_DEBUG("\tOpen file '%s'", path_.c_str());
107   std::map<std::string, sg_size_t>* content = nullptr;
108   if (local_storage_)
109     content = local_storage_->extension<FileSystemStorageExt>()->get_content();
110
111   if (local_disk_)
112     content = local_disk_->extension<FileSystemDiskExt>()->get_content();
113
114   // if file does not exist create an empty file
115   if (content) {
116     auto sz = content->find(path_);
117     if (sz != content->end()) {
118       size_ = sz->second;
119     } else {
120       size_ = 0;
121       content->insert({path_, size_});
122       XBT_DEBUG("File '%s' was not found, file created.", path_.c_str());
123     }
124   }
125 }
126
127 File::~File()
128 {
129   Host::current()->extension<simgrid::s4u::FileDescriptorHostExt>()->file_descriptor_table->push_back(desc_id);
130 }
131
132 void File::dump()
133 {
134   if (local_storage_)
135     XBT_INFO("File Descriptor information:\n"
136              "\t\tFull path: '%s'\n"
137              "\t\tSize: %llu\n"
138              "\t\tMount point: '%s'\n"
139              "\t\tStorage Id: '%s'\n"
140              "\t\tStorage Type: '%s'\n"
141              "\t\tFile Descriptor Id: %d",
142              get_path(), size_, mount_point_.c_str(), local_storage_->get_cname(), local_storage_->get_type(), desc_id);
143   if (local_disk_)
144     XBT_INFO("File Descriptor information:\n"
145              "\t\tFull path: '%s'\n"
146              "\t\tSize: %llu\n"
147              "\t\tMount point: '%s'\n"
148              "\t\tDisk Id: '%s'\n"
149              "\t\tHost Id: '%s'\n"
150              "\t\tFile Descriptor Id: %d",
151              get_path(), size_, mount_point_.c_str(), local_disk_->get_cname(), local_disk_->get_host()->get_cname(),
152              desc_id);
153 }
154
155 sg_size_t File::read(sg_size_t size)
156 {
157   if (size_ == 0) /* Nothing to read, return */
158     return 0;
159   sg_size_t read_size = 0;
160   Host* host          = nullptr;
161   if (local_storage_) {
162     /* Find the host where the file is physically located and read it */
163     host = local_storage_->get_host();
164     XBT_DEBUG("READ %s on disk '%s'", get_path(), local_storage_->get_cname());
165     // if the current position is close to the end of the file, we may not be able to read the requested size
166     read_size = local_storage_->read(std::min(size, size_ - current_position_));
167     current_position_ += read_size;
168   }
169
170   if (local_disk_) {
171     /* Find the host where the file is physically located and read it */
172     host = local_disk_->get_host();
173     XBT_DEBUG("READ %s on disk '%s'", get_path(), local_disk_->get_cname());
174     // if the current position is close to the end of the file, we may not be able to read the requested size
175     read_size = local_disk_->read(std::min(size, size_ - current_position_));
176     current_position_ += read_size;
177   }
178
179   if (host && host->get_name() != Host::current()->get_name() && read_size > 0) {
180     /* the file is hosted on a remote host, initiate a communication between src and dest hosts for data transfer */
181     XBT_DEBUG("File is on %s remote host, initiate data transfer of %llu bytes.", host->get_cname(), read_size);
182     host->send_to(Host::current(), read_size);
183   }
184
185   return read_size;
186 }
187
188 /** @brief Write into a file (local or remote)
189  *
190  * @param size of the file to write
191  * @return the number of bytes successfully write or -1 if an error occurred
192  */
193 sg_size_t File::write_on_disk(sg_size_t size, bool write_inside)
194 {
195   sg_size_t write_size = 0;
196   /* Find the host where the file is physically located (remote or local)*/
197   Host* host = local_disk_->get_host();
198
199   if (host && host->get_name() != Host::current()->get_name()) {
200     /* the file is hosted on a remote host, initiate a communication between src and dest hosts for data transfer */
201     XBT_DEBUG("File is on %s remote host, initiate data transfer of %llu bytes.", host->get_cname(), size);
202     Host::current()->send_to(host, size);
203   }
204   XBT_DEBUG("WRITE %s on disk '%s'. size '%llu/%llu' '%llu:%llu'", get_path(), local_disk_->get_cname(), size, size_,
205             sg_disk_get_size_used(local_disk_), sg_disk_get_size(local_disk_));
206   // If the storage is full before even starting to write
207   if (sg_disk_get_size_used(local_disk_) >= sg_disk_get_size(local_disk_))
208     return 0;
209   if (not write_inside) {
210     /* Subtract the part of the file that might disappear from the used sized on the storage element */
211     local_disk_->extension<FileSystemDiskExt>()->decr_used_size(size_ - current_position_);
212     write_size = local_disk_->write(size);
213     local_disk_->extension<FileSystemDiskExt>()->incr_used_size(write_size);
214     current_position_ += write_size;
215     size_ = current_position_;
216   } else {
217     write_size = local_disk_->write(size);
218     current_position_ += write_size;
219     if (current_position_ > size_)
220       size_ = current_position_;
221   }
222   std::map<std::string, sg_size_t>* content = local_disk_->extension<FileSystemDiskExt>()->get_content();
223
224   content->erase(path_);
225   content->insert({path_, size_});
226
227   return write_size;
228 }
229
230 sg_size_t File::write_on_storage(sg_size_t size, bool write_inside)
231 {
232   sg_size_t write_size = 0;
233   /* Find the host where the file is physically located (remote or local)*/
234   Host* host = local_storage_->get_host();
235
236   if (host && host->get_name() != Host::current()->get_name()) {
237     /* the file is hosted on a remote host, initiate a communication between src and dest hosts for data transfer */
238     XBT_DEBUG("File is on %s remote host, initiate data transfer of %llu bytes.", host->get_cname(), size);
239     Host::current()->send_to(host, size);
240   }
241
242   XBT_DEBUG("WRITE %s on disk '%s'. size '%llu/%llu' '%llu:%llu'", get_path(), local_storage_->get_cname(), size, size_,
243             sg_storage_get_size_used(local_storage_), sg_storage_get_size(local_storage_));
244   // If the storage is full before even starting to write
245   if (sg_storage_get_size_used(local_storage_) >= sg_storage_get_size(local_storage_))
246     return 0;
247   if (not write_inside) {
248     /* Subtract the part of the file that might disappear from the used sized on the storage element */
249     local_storage_->extension<FileSystemStorageExt>()->decr_used_size(size_ - current_position_);
250     write_size = local_storage_->write(size);
251     local_storage_->extension<FileSystemStorageExt>()->incr_used_size(write_size);
252     current_position_ += write_size;
253     size_ = current_position_;
254   } else {
255     write_size = local_storage_->write(size);
256     current_position_ += write_size;
257     if (current_position_ > size_)
258       size_ = current_position_;
259   }
260   std::map<std::string, sg_size_t>* content = local_storage_->extension<FileSystemStorageExt>()->get_content();
261
262   content->erase(path_);
263   content->insert({path_, size_});
264
265   return write_size;
266 }
267
268 sg_size_t File::write(sg_size_t size, bool write_inside)
269 {
270   if (size == 0) /* Nothing to write, return */
271     return 0;
272
273   if (local_disk_)
274     return write_on_disk(size, write_inside);
275   if (local_storage_)
276     return write_on_storage(size, write_inside);
277
278   return 0;
279 }
280
281 sg_size_t File::size()
282 {
283   return size_;
284 }
285
286 void File::seek(sg_offset_t offset)
287 {
288   current_position_ = offset;
289 }
290
291 void File::seek(sg_offset_t offset, int origin)
292 {
293   switch (origin) {
294     case SEEK_SET:
295       current_position_ = offset;
296       break;
297     case SEEK_CUR:
298       current_position_ += offset;
299       break;
300     case SEEK_END:
301       current_position_ = size_ + offset;
302       break;
303     default:
304       break;
305   }
306 }
307
308 sg_size_t File::tell()
309 {
310   return current_position_;
311 }
312
313 void File::move(const std::string& fullpath)
314 {
315   /* Check if the new full path is on the same mount point */
316   if (fullpath.compare(0, mount_point_.length(), mount_point_) == 0) {
317     std::map<std::string, sg_size_t>* content = nullptr;
318     if (local_storage_)
319       content = local_storage_->extension<FileSystemStorageExt>()->get_content();
320     if (local_disk_)
321       content = local_disk_->extension<FileSystemDiskExt>()->get_content();
322     if (content) {
323       auto sz = content->find(path_);
324       if (sz != content->end()) { // src file exists
325         sg_size_t new_size = sz->second;
326         content->erase(path_);
327         std::string path = fullpath.substr(mount_point_.length(), fullpath.length());
328         content->insert({path.c_str(), new_size});
329         XBT_DEBUG("Move file from %s to %s, size '%llu'", path_.c_str(), fullpath.c_str(), new_size);
330       } else {
331         XBT_WARN("File %s doesn't exist", path_.c_str());
332       }
333     }
334   } else {
335     XBT_WARN("New full path %s is not on the same mount point: %s.", fullpath.c_str(), mount_point_.c_str());
336   }
337 }
338
339 int File::unlink()
340 {
341   /* Check if the file is on local storage */
342   std::map<std::string, sg_size_t>* content = nullptr;
343   const char* name = "";
344   if (local_storage_) {
345     content = local_storage_->extension<FileSystemStorageExt>()->get_content();
346     name    = local_storage_->get_cname();
347   }
348   if (local_disk_) {
349     content = local_disk_->extension<FileSystemDiskExt>()->get_content();
350     name    = local_disk_->get_cname();
351   }
352
353   if (not content || content->find(path_) == content->end()) {
354     XBT_WARN("File %s is not on disk %s. Impossible to unlink", path_.c_str(), name);
355     return -1;
356   } else {
357     XBT_DEBUG("UNLINK %s on disk '%s'", path_.c_str(), name);
358
359     if (local_storage_)
360       local_storage_->extension<FileSystemStorageExt>()->decr_used_size(size_);
361
362     if (local_disk_)
363       local_disk_->extension<FileSystemDiskExt>()->decr_used_size(size_);
364
365     // Remove the file from storage
366     content->erase(path_);
367
368     return 0;
369   }
370 }
371
372 int File::remote_copy(sg_host_t host, const char* fullpath)
373 {
374   /* Find the host where the file is physically located and read it */
375   Host* src_host = nullptr;
376   if (local_storage_) {
377     src_host = local_storage_->get_host();
378     XBT_DEBUG("READ %s on disk '%s'", get_path(), local_storage_->get_cname());
379   }
380
381   if (local_disk_) {
382     src_host = local_disk_->get_host();
383     XBT_DEBUG("READ %s on disk '%s'", get_path(), local_disk_->get_cname());
384   }
385
386   seek(0, SEEK_SET);
387   // if the current position is close to the end of the file, we may not be able to read the requested size
388   sg_size_t read_size = 0;
389   if (local_storage_)
390     read_size = local_storage_->read(size_);
391   if (local_disk_)
392     read_size = local_disk_->read(size_);
393
394   current_position_ += read_size;
395
396   Host* dst_host = host;
397   size_t longest_prefix_length = 0;
398   if (local_storage_) {
399     /* Find the host that owns the storage where the file has to be copied */
400     Storage* storage_dest        = nullptr;
401
402     for (auto const& elm : host->get_mounted_storages()) {
403       std::string mount_point = std::string(fullpath).substr(0, elm.first.size());
404       if (mount_point == elm.first && elm.first.length() > longest_prefix_length) {
405         /* The current mount name is found in the full path and is bigger than the previous*/
406         longest_prefix_length = elm.first.length();
407         storage_dest          = elm.second;
408       }
409     }
410
411     if (storage_dest != nullptr) {
412       /* Mount point found, retrieve the host the storage is attached to */
413       dst_host = storage_dest->get_host();
414     } else {
415       XBT_WARN("Can't find mount point for '%s' on destination host '%s'", fullpath, host->get_cname());
416       return -1;
417     }
418   }
419
420   if (local_disk_) {
421     Disk* dst_disk               = nullptr;
422
423     for (auto const& disk : host->get_disks()) {
424       std::string current_mount = disk->extension<FileSystemDiskExt>()->get_mount_point();
425       std::string mount_point   = std::string(fullpath).substr(0, current_mount.length());
426       if (mount_point == current_mount && current_mount.length() > longest_prefix_length) {
427         /* The current mount name is found in the full path and is bigger than the previous*/
428         longest_prefix_length = current_mount.length();
429         dst_disk              = disk;
430       }
431     }
432
433     if (dst_disk == nullptr) {
434       XBT_WARN("Can't find mount point for '%s' on destination host '%s'", fullpath, host->get_cname());
435       return -1;
436     }
437   }
438
439   if (src_host) {
440     XBT_DEBUG("Initiate data transfer of %llu bytes between %s and %s.", read_size, src_host->get_cname(),
441               dst_host->get_cname());
442     src_host->send_to(dst_host, read_size);
443   }
444
445   /* Create file on remote host, write it and close it */
446   File* fd = new File(fullpath, dst_host, nullptr);
447   if (local_storage_) {
448     sg_size_t write_size = fd->local_storage_->write(read_size);
449     fd->local_storage_->extension<FileSystemStorageExt>()->incr_used_size(write_size);
450     (*(fd->local_storage_->extension<FileSystemStorageExt>()->get_content()))[path_] = size_;
451   }
452   if (local_disk_)
453     fd->write(read_size);
454   delete fd;
455   return 0;
456 }
457
458 int File::remote_move(sg_host_t host, const char* fullpath)
459 {
460   int res = remote_copy(host, fullpath);
461   unlink();
462   return res;
463 }
464
465 FileSystemDiskExt::FileSystemDiskExt(simgrid::s4u::Disk* ptr)
466 {
467   const char* size_str    = ptr->get_property("size");
468   if (size_str)
469     size_ = surf_parse_get_size(size_str, "disk size", ptr->get_name());
470
471   const char* current_mount_str = ptr->get_property("mount");
472   if (current_mount_str)
473     mount_point_ = std::string(current_mount_str);
474   else
475     mount_point_ = std::string("/");
476
477   const char* content_str = ptr->get_property("content");
478   if (content_str)
479     content_.reset(parse_content(content_str));
480 }
481
482 FileSystemStorageExt::FileSystemStorageExt(simgrid::s4u::Storage* ptr)
483 {
484   content_.reset(parse_content(ptr->get_impl()->content_name_));
485   size_    = ptr->get_impl()->size_;
486 }
487
488 std::map<std::string, sg_size_t>* FileSystemDiskExt::parse_content(const std::string& filename)
489 {
490   if (filename.empty())
491     return nullptr;
492
493   std::map<std::string, sg_size_t>* parse_content = new std::map<std::string, sg_size_t>();
494
495   std::ifstream* fs = surf_ifsopen(filename);
496
497   std::string line;
498   std::vector<std::string> tokens;
499   do {
500     std::getline(*fs, line);
501     boost::trim(line);
502     if (line.length() > 0) {
503       boost::split(tokens, line, boost::is_any_of(" \t"), boost::token_compress_on);
504       xbt_assert(tokens.size() == 2, "Parse error in %s: %s", filename.c_str(), line.c_str());
505       sg_size_t size = std::stoull(tokens.at(1));
506
507       used_size_ += size;
508       parse_content->insert({tokens.front(), size});
509     }
510   } while (not fs->eof());
511   delete fs;
512   return parse_content;
513 }
514
515 std::map<std::string, sg_size_t>* FileSystemStorageExt::parse_content(const std::string& filename)
516 {
517   if (filename.empty())
518     return nullptr;
519
520   std::map<std::string, sg_size_t>* parse_content = new std::map<std::string, sg_size_t>();
521
522   std::ifstream* fs = surf_ifsopen(filename);
523
524   std::string line;
525   std::vector<std::string> tokens;
526   do {
527     std::getline(*fs, line);
528     boost::trim(line);
529     if (line.length() > 0) {
530       boost::split(tokens, line, boost::is_any_of(" \t"), boost::token_compress_on);
531       xbt_assert(tokens.size() == 2, "Parse error in %s: %s", filename.c_str(), line.c_str());
532       sg_size_t size = std::stoull(tokens.at(1));
533
534       used_size_ += size;
535       parse_content->insert({tokens.front(), size});
536     }
537   } while (not fs->eof());
538   delete fs;
539   return parse_content;
540 }
541 }
542 }
543
544 using simgrid::s4u::FileDescriptorHostExt;
545 using simgrid::s4u::FileSystemDiskExt;
546 using simgrid::s4u::FileSystemStorageExt;
547
548 static void on_disk_creation(simgrid::s4u::Disk& d)
549 {
550   d.extension_set(new FileSystemDiskExt(&d));
551 }
552 static void on_storage_creation(simgrid::s4u::Storage& st)
553 {
554   st.extension_set(new FileSystemStorageExt(&st));
555 }
556
557 static void on_host_creation(simgrid::s4u::Host& host)
558 {
559   host.extension_set<FileDescriptorHostExt>(new FileDescriptorHostExt());
560 }
561
562 static void on_platform_created()
563 {
564   for (auto const& host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
565     const char* remote_disk_str = host->get_property("remote_disk");
566     if (remote_disk_str) {
567       std::vector<std::string> tokens;
568       boost::split(tokens, remote_disk_str, boost::is_any_of(":"));
569       std::string mount_point         = tokens[0];
570       simgrid::s4u::Host* remote_host = simgrid::s4u::Host::by_name_or_null(tokens[2]);
571       xbt_assert(remote_host, "You're trying to access a host that does not exist. Please check your platform file");
572
573       simgrid::s4u::Disk* disk = nullptr;
574       for (auto const& d : remote_host->get_disks())
575         if (d->get_name() == tokens[1]) {
576           disk = d;
577           break;
578         }
579
580       xbt_assert(disk, "You're trying to mount a disk that does not exist. Please check your platform file");
581       disk->extension<FileSystemDiskExt>()->add_remote_mount(remote_host, mount_point);
582       host->add_disk(disk);
583
584       XBT_DEBUG("Host '%s' wants to mount a remote disk: %s of %s mounted on %s", host->get_cname(), disk->get_cname(),
585                 remote_host->get_cname(), mount_point.c_str());
586       XBT_DEBUG("Host '%s' now has %zu disks", host->get_cname(), host->get_disks().size());
587     }
588   }
589 }
590
591 static void on_simulation_end()
592 {
593   XBT_DEBUG("Simulation is over, time to unregister remote disks if any");
594   for (auto const& host : simgrid::s4u::Engine::get_instance()->get_all_hosts()) {
595     const char* remote_disk_str = host->get_property("remote_disk");
596     if (remote_disk_str) {
597       std::vector<std::string> tokens;
598       boost::split(tokens, remote_disk_str, boost::is_any_of(":"));
599       XBT_DEBUG("Host '%s' wants to unmount a remote disk: %s of %s mounted on %s", host->get_cname(),
600                 tokens[1].c_str(), tokens[2].c_str(), tokens[0].c_str());
601       host->remove_disk(tokens[1]);
602       XBT_DEBUG("Host '%s' now has %zu disks", host->get_cname(), host->get_disks().size());
603     }
604   }
605 }
606
607 /* **************************** Public interface *************************** */
608 void sg_storage_file_system_init()
609 {
610   sg_storage_max_file_descriptors = 1024;
611   simgrid::config::bind_flag(sg_storage_max_file_descriptors, "storage/max_file_descriptors",
612                              "Maximum number of concurrently opened files per host. Default is 1024");
613
614   if (not FileSystemStorageExt::EXTENSION_ID.valid()) {
615     FileSystemStorageExt::EXTENSION_ID = simgrid::s4u::Storage::extension_create<FileSystemStorageExt>();
616     simgrid::s4u::Storage::on_creation.connect(&on_storage_creation);
617   }
618
619   if (not FileSystemDiskExt::EXTENSION_ID.valid()) {
620     FileSystemDiskExt::EXTENSION_ID = simgrid::s4u::Disk::extension_create<FileSystemDiskExt>();
621     simgrid::s4u::Disk::on_creation.connect(&on_disk_creation);
622   }
623
624   if (not FileDescriptorHostExt::EXTENSION_ID.valid()) {
625     FileDescriptorHostExt::EXTENSION_ID = simgrid::s4u::Host::extension_create<FileDescriptorHostExt>();
626     simgrid::s4u::Host::on_creation.connect(&on_host_creation);
627   }
628   simgrid::s4u::Engine::on_platform_created.connect(&on_platform_created);
629   simgrid::s4u::Engine::on_simulation_end.connect(&on_simulation_end);
630 }
631
632 sg_file_t sg_file_open(const char* fullpath, void* data)
633 {
634   return new simgrid::s4u::File(fullpath, data);
635 }
636
637 sg_size_t sg_file_read(sg_file_t fd, sg_size_t size)
638 {
639   return fd->read(size);
640 }
641
642 sg_size_t sg_file_write(sg_file_t fd, sg_size_t size)
643 {
644   return fd->write(size);
645 }
646
647 void sg_file_close(sg_file_t fd)
648 {
649   delete fd;
650 }
651
652 const char* sg_file_get_name(sg_file_t fd)
653 {
654   xbt_assert((fd != nullptr), "Invalid file descriptor");
655   return fd->get_path();
656 }
657
658 sg_size_t sg_file_get_size(sg_file_t fd)
659 {
660   return fd->size();
661 }
662
663 void sg_file_dump(sg_file_t fd)
664 {
665   fd->dump();
666 }
667
668 void* sg_file_get_data(sg_file_t fd)
669 {
670   return fd->get_data();
671 }
672
673 void sg_file_set_data(sg_file_t fd, void* data)
674 {
675   fd->set_data(data);
676 }
677
678 /**
679  * @brief Set the file position indicator in the sg_file_t by adding offset bytes
680  * to the position specified by origin (either SEEK_SET, SEEK_CUR, or SEEK_END).
681  *
682  * @param fd : file object that identifies the stream
683  * @param offset : number of bytes to offset from origin
684  * @param origin : Position used as reference for the offset. It is specified by one of the following constants defined
685  *                 in \<stdio.h\> exclusively to be used as arguments for this function (SEEK_SET = beginning of file,
686  *                 SEEK_CUR = current position of the file pointer, SEEK_END = end of file)
687  */
688 void sg_file_seek(sg_file_t fd, sg_offset_t offset, int origin)
689 {
690   fd->seek(offset, origin);
691 }
692
693 sg_size_t sg_file_tell(sg_file_t fd)
694 {
695   return fd->tell();
696 }
697
698 void sg_file_move(sg_file_t fd, const char* fullpath)
699 {
700   fd->move(fullpath);
701 }
702
703 void sg_file_unlink(sg_file_t fd)
704 {
705   fd->unlink();
706   delete fd;
707 }
708
709 /**
710  * @brief Copy a file to another location on a remote host.
711  * @param file : the file to move
712  * @param host : the remote host where the file has to be copied
713  * @param fullpath : the complete path destination on the remote host
714  * @return If successful, the function returns 0. Otherwise, it returns -1.
715  */
716 int sg_file_rcopy(sg_file_t file, sg_host_t host, const char* fullpath)
717 {
718   return file->remote_copy(host, fullpath);
719 }
720
721 /**
722  * @brief Move a file to another location on a remote host.
723  * @param file : the file to move
724  * @param host : the remote host where the file has to be moved
725  * @param fullpath : the complete path destination on the remote host
726  * @return If successful, the function returns 0. Otherwise, it returns -1.
727  */
728 int sg_file_rmove(sg_file_t file, sg_host_t host, const char* fullpath)
729 {
730   return file->remote_move(host, fullpath);
731 }
732
733 sg_size_t sg_disk_get_size_free(sg_disk_t d)
734 {
735   return d->extension<FileSystemDiskExt>()->get_size() - d->extension<FileSystemDiskExt>()->get_used_size();
736 }
737
738 sg_size_t sg_disk_get_size_used(sg_disk_t d)
739 {
740   return d->extension<FileSystemDiskExt>()->get_used_size();
741 }
742
743 sg_size_t sg_disk_get_size(sg_disk_t d)
744 {
745   return d->extension<FileSystemDiskExt>()->get_size();
746 }
747
748 const char* sg_disk_get_mount_point(sg_disk_t d)
749 {
750   return d->extension<FileSystemDiskExt>()->get_mount_point();
751 }
752
753 sg_size_t sg_storage_get_size_free(sg_storage_t st)
754 {
755   return st->extension<FileSystemStorageExt>()->get_size() - st->extension<FileSystemStorageExt>()->get_used_size();
756 }
757
758 sg_size_t sg_storage_get_size_used(sg_storage_t st)
759 {
760   return st->extension<FileSystemStorageExt>()->get_used_size();
761 }
762
763 sg_size_t sg_storage_get_size(sg_storage_t st)
764 {
765   return st->extension<FileSystemStorageExt>()->get_size();
766 }
767
768 xbt_dict_t sg_storage_get_content(sg_storage_t storage)
769 {
770   std::map<std::string, sg_size_t>* content = storage->extension<simgrid::s4u::FileSystemStorageExt>()->get_content();
771   // Note: ::operator delete is ok here (no destructor called) since the dict elements are of POD type sg_size_t.
772   xbt_dict_t content_as_dict = xbt_dict_new_homogeneous(::operator delete);
773
774   for (auto const& entry : *content) {
775     sg_size_t* psize = new sg_size_t;
776     *psize           = entry.second;
777     xbt_dict_set(content_as_dict, entry.first.c_str(), psize);
778   }
779   return content_as_dict;
780 }
781
782 xbt_dict_t sg_host_get_storage_content(sg_host_t host)
783 {
784   xbt_assert((host != nullptr), "Invalid parameters");
785   xbt_dict_t contents = xbt_dict_new_homogeneous(nullptr);
786   for (auto const& elm : host->get_mounted_storages())
787     xbt_dict_set(contents, elm.first.c_str(), sg_storage_get_content(elm.second));
788
789   return contents;
790 }