Logo AND Algorithmique Numérique Distribuée

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