diff --git a/src/common_io.c b/src/common_io.c
index aba1595df6d59d13f0e1a1e2f879f4ab2248de84..e28496340f424405475e2b13bca19f960411c733 100644
--- a/src/common_io.c
+++ b/src/common_io.c
@@ -2492,3 +2492,47 @@ void io_make_snapshot_subdir(const char* dirname) {
     safe_checkdir(dirname, /*create=*/1);
   }
 }
+
+/**
+ * @brief Construct the file names for a single-file hdf5 snapshots and
+ *
+ * @param filename (return) The file name of the hdf5 snapshot.
+ * @param xmf_filename (return) The file name of the associated XMF file.
+ * @param use_time_label Are we using time labels for the snapshot indices?
+ * @param snapshots_invoke_stf Are we calling STF when dumping a snapshot?
+ * @param time The current simulation time.
+ * @param stf_count The counter of STF outputs.
+ * @param snap_count The counter of snapshot outputs.
+ * @param subdir The sub-directory in which the snapshots are written.
+ * @param basename The common part of the snapshot names.
+ */
+void io_get_snapshot_filename(char filename[1024], char xmf_filename[1024],
+                              const int use_time_label,
+                              const int snapshots_invoke_stf, const double time,
+                              const int stf_count, const int snap_count,
+                              const char* subdir, const char* basename) {
+
+  int snap_number = -1;
+  if (use_time_label)
+    snap_number = (int)round(time);
+  else if (snapshots_invoke_stf)
+    snap_number = stf_count;
+  else
+    snap_number = snap_count;
+
+  int number_digits = -1;
+  if (use_time_label)
+    number_digits = 6;
+  else
+    number_digits = 4;
+
+  /* Are we using a sub-dir? */
+  if (strlen(subdir) > 0) {
+    sprintf(filename, "%s/%s_%0*d.hdf5", subdir, basename, number_digits,
+            snap_number);
+    sprintf(xmf_filename, "%s/%s.xmf", subdir, basename);
+  } else {
+    sprintf(filename, "%s_%0*d.hdf5", basename, number_digits, snap_number);
+    sprintf(xmf_filename, "%s.xmf", basename);
+  }
+}
diff --git a/src/common_io.h b/src/common_io.h
index bb1564cee5b673b0e8526401868de0855a10c194..2a6392dc69fe03f0fba5511ca6936e5d1e0ce8e9 100644
--- a/src/common_io.h
+++ b/src/common_io.h
@@ -174,4 +174,10 @@ void io_write_output_field_parameter(const char* filename);
 
 void io_make_snapshot_subdir(const char* dirname);
 
+void io_get_snapshot_filename(char filename[1024], char xmf_filename[1024],
+                              const int use_time_label,
+                              const int snapshots_invoke_stf, const double time,
+                              const int stf_count, const int snap_count,
+                              const char* subdir, const char* basename);
+
 #endif /* SWIFT_COMMON_IO_H */
diff --git a/src/engine.c b/src/engine.c
index a2622f70d280abed2511e35f1d7fb7f15daf6273..ae82c8e03d5d25ee71bfe2b2b1411ee4f7af2cb1 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -3587,22 +3587,6 @@ void engine_dump_snapshot(struct engine *e) {
   engine_collect_stars_counter(e);
 #endif
 
-  /* Determine snapshot location */
-  char snapshotBase[FILENAME_BUFFER_SIZE];
-  if (strnlen(e->snapshot_subdir, PARSER_MAX_LINE_SIZE) > 0) {
-    if (snprintf(snapshotBase, FILENAME_BUFFER_SIZE, "%s/%s",
-                 e->snapshot_subdir,
-                 e->snapshot_base_name) >= FILENAME_BUFFER_SIZE) {
-      error(
-          "FILENAME_BUFFER_SIZE is too small for snapshot path and file name");
-    }
-  } else {
-    if (snprintf(snapshotBase, FILENAME_BUFFER_SIZE, "%s",
-                 e->snapshot_base_name) >= FILENAME_BUFFER_SIZE) {
-      error("FILENAME_BUFFER_SIZE is too small for snapshot file name");
-    }
-  }
-
 /* Dump (depending on the chosen strategy) ... */
 #if defined(HAVE_HDF5)
 #if defined(WITH_MPI)
@@ -3614,16 +3598,15 @@ void engine_dump_snapshot(struct engine *e) {
   } else {
 
 #if defined(HAVE_PARALLEL_HDF5)
-    write_output_parallel(e, snapshotBase, e->internal_units, e->snapshot_units,
-                          e->nodeID, e->nr_nodes, MPI_COMM_WORLD,
-                          MPI_INFO_NULL);
+    write_output_parallel(e, e->internal_units, e->snapshot_units, e->nodeID,
+                          e->nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL);
 #else
-    write_output_serial(e, snapshotBase, e->internal_units, e->snapshot_units,
-                        e->nodeID, e->nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL);
+    write_output_serial(e, e->internal_units, e->snapshot_units, e->nodeID,
+                        e->nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL);
 #endif
   }
 #else
-  write_output_single(e, snapshotBase, e->internal_units, e->snapshot_units);
+  write_output_single(e, e->internal_units, e->snapshot_units);
 #endif
 #endif
 
diff --git a/src/parallel_io.c b/src/parallel_io.c
index 686b6ab600ffaf8ec14b3a011e263eb62536ea49..5f26423800357ecd8d5a8c81a94dfb047ff43e13 100644
--- a/src/parallel_io.c
+++ b/src/parallel_io.c
@@ -378,7 +378,7 @@ void read_array_parallel(hid_t grp, struct io_props props, size_t N,
  * @param N_total The total number of particles to write in this array.
  * @param snapshot_units The units used for the data in this snapshot.
  */
-void prepare_array_parallel(struct engine* e, hid_t grp, char* fileName,
+void prepare_array_parallel(struct engine* e, hid_t grp, const char* fileName,
                             FILE* xmfFile, char* partTypeGroupName,
                             struct io_props props, long long N_total,
                             const struct unit_system* snapshot_units) {
@@ -1041,12 +1041,12 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
  * @brief Prepares a file for a parallel write.
  *
  * @param e The #engine.
- * @param baseName The base name of the snapshots.
  * @param N_total The total number of particles of each type to write.
  * @param internal_units The #unit_system used internally.
  * @param snapshot_units The #unit_system used in the snapshots.
  */
-void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
+void prepare_file(struct engine* e, const char* fileName,
+                  const char* xmfFileName, long long N_total[6],
                   const struct unit_system* internal_units,
                   const struct unit_system* snapshot_units) {
 
@@ -1071,23 +1071,10 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
   int numFiles = 1;
 
   /* First time, we need to create the XMF file */
-  if (e->snapshot_output_count == 0) xmf_create_file(baseName);
+  if (e->snapshot_output_count == 0) xmf_create_file(xmfFileName);
 
   /* Prepare the XMF file for the new entry */
-  xmfFile = xmf_prepare_file(baseName);
-
-  /* HDF5 File name */
-  char fileName[FILENAME_BUFFER_SIZE];
-  if (e->snapshot_int_time_label_on)
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName,
-             (int)round(e->time));
-  else if (e->snapshot_invoke_stf) {
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->stf_output_count);
-  } else {
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->snapshot_output_count);
-  }
+  xmfFile = xmf_prepare_file(xmfFileName);
 
   /* Open HDF5 file with the chosen parameters */
   hid_t h_file = H5Fcreate(fileName, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
@@ -1301,7 +1288,6 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
  *its XMF descriptor
  *
  * @param e The engine containing all the system.
- * @param baseName The common part of the snapshot file name.
  * @param internal_units The #unit_system used internally
  * @param snapshot_units The #unit_system used in the snapshots
  * @param mpi_rank The MPI rank of this node.
@@ -1317,7 +1303,7 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
  * Calls #error() if an error occurs.
  *
  */
-void write_output_parallel(struct engine* e, const char* baseName,
+void write_output_parallel(struct engine* e,
                            const struct unit_system* internal_units,
                            const struct unit_system* snapshot_units,
                            int mpi_rank, int mpi_size, MPI_Comm comm,
@@ -1389,9 +1375,18 @@ void write_output_parallel(struct engine* e, const char* baseName,
   ticks tic = getticks();
 #endif
 
+  /* File names */
+  char fileName[FILENAME_BUFFER_SIZE];
+  char xmfFileName[FILENAME_BUFFER_SIZE];
+  io_get_snapshot_filename(fileName, xmfFileName, e->snapshot_int_time_label_on,
+                           e->snapshot_invoke_stf, e->time, e->stf_output_count,
+                           e->snapshot_output_count, e->snapshot_subdir,
+                           e->snapshot_base_name);
+
   /* Rank 0 prepares the file */
   if (mpi_rank == 0)
-    prepare_file(e, baseName, N_total, internal_units, snapshot_units);
+    prepare_file(e, fileName, xmfFileName, N_total, internal_units,
+                 snapshot_units);
 
   MPI_Barrier(MPI_COMM_WORLD);
 
@@ -1403,19 +1398,6 @@ void write_output_parallel(struct engine* e, const char* baseName,
   tic = getticks();
 #endif
 
-  /* HDF5 File name */
-  char fileName[FILENAME_BUFFER_SIZE];
-  if (e->snapshot_int_time_label_on)
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName,
-             (int)round(e->time));
-  else if (e->snapshot_invoke_stf) {
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->stf_output_count);
-  } else {
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->snapshot_output_count);
-  }
-
   /* Now write the top-level cell structure */
   hid_t h_file_cells = 0, h_grp_cells = 0;
   if (mpi_rank == 0) {
diff --git a/src/parallel_io.h b/src/parallel_io.h
index 08588ee3d3292e5a765a9941c10f72e6aab82a2a..b816d1d7c6fa74cf1ec83bba2bbf768639811f17 100644
--- a/src/parallel_io.h
+++ b/src/parallel_io.h
@@ -44,7 +44,7 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
                       int mpi_size, MPI_Comm comm, MPI_Info info,
                       int nr_threads, int dry_run);
 
-void write_output_parallel(struct engine* e, const char* baseName,
+void write_output_parallel(struct engine* e,
                            const struct unit_system* internal_units,
                            const struct unit_system* snapshot_units,
                            int mpi_rank, int mpi_size, MPI_Comm comm,
diff --git a/src/serial_io.c b/src/serial_io.c
index 74e936257589b57bf4e68c9f2a9abfe65bdd0246..58b8f284515086866c9dd4da4f0879800d5ee254 100644
--- a/src/serial_io.c
+++ b/src/serial_io.c
@@ -841,7 +841,6 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
  * @brief Writes an HDF5 output file (GADGET-3 type) with its XMF descriptor
  *
  * @param e The engine containing all the system.
- * @param baseName The common part of the snapshot file name.
  * @param internal_units The #unit_system used internally
  * @param snapshot_units The #unit_system used in the snapshots
  * @param mpi_rank The MPI rank of this node.
@@ -857,7 +856,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
  * Calls #error() if an error occurs.
  *
  */
-void write_output_serial(struct engine* e, const char* baseName,
+void write_output_serial(struct engine* e,
                          const struct unit_system* internal_units,
                          const struct unit_system* snapshot_units, int mpi_rank,
                          int mpi_size, MPI_Comm comm, MPI_Info info) {
@@ -914,16 +913,11 @@ void write_output_serial(struct engine* e, const char* baseName,
 
   /* File name */
   char fileName[FILENAME_BUFFER_SIZE];
-  if (e->snapshot_int_time_label_on)
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName,
-             (int)round(e->time));
-  else if (e->snapshot_invoke_stf) {
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->stf_output_count);
-  } else {
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->snapshot_output_count);
-  }
+  char xmfFileName[FILENAME_BUFFER_SIZE];
+  io_get_snapshot_filename(fileName, xmfFileName, e->snapshot_int_time_label_on,
+                           e->snapshot_invoke_stf, e->time, e->stf_output_count,
+                           e->snapshot_output_count, e->snapshot_subdir,
+                           e->snapshot_base_name);
 
   /* Compute offset in the file and total number of particles */
   size_t N[swift_type_count] = {Ngas_written,   Ndm_written,
@@ -945,10 +939,10 @@ void write_output_serial(struct engine* e, const char* baseName,
   if (mpi_rank == 0) {
 
     /* First time, we need to create the XMF file */
-    if (e->snapshot_output_count == 0) xmf_create_file(baseName);
+    if (e->snapshot_output_count == 0) xmf_create_file(xmfFileName);
 
     /* Prepare the XMF file for the new entry */
-    xmfFile = xmf_prepare_file(baseName);
+    xmfFile = xmf_prepare_file(xmfFileName);
 
     /* Write the part corresponding to this specific output */
     xmf_write_outputheader(xmfFile, fileName, e->time);
diff --git a/src/serial_io.h b/src/serial_io.h
index 1146e5f5fb9767f94c5e76195cabbc893db25e14..764bcf9ca571f06a0e3c9ba389079f072bd61d0f 100644
--- a/src/serial_io.h
+++ b/src/serial_io.h
@@ -45,7 +45,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
                     double h, double a, int mpi_rank, int mpi_size,
                     MPI_Comm comm, MPI_Info info, int n_threads, int dry_run);
 
-void write_output_serial(struct engine* e, const char* baseName,
+void write_output_serial(struct engine* e,
                          const struct unit_system* internal_units,
                          const struct unit_system* snapshot_units, int mpi_rank,
                          int mpi_size, MPI_Comm comm, MPI_Info info);
diff --git a/src/single_io.c b/src/single_io.c
index bb4a548222f73817774faccdc0082d68bd7a48d0..2cc44cc59ad376b483bae87ebe922989ac1b9c8d 100644
--- a/src/single_io.c
+++ b/src/single_io.c
@@ -705,7 +705,6 @@ void read_ic_single(const char* fileName,
  * @brief Writes an HDF5 output file (GADGET-3 type) with its XMF descriptor
  *
  * @param e The engine containing all the system.
- * @param baseName The common part of the snapshot file name.
  * @param internal_units The #unit_system used internally
  * @param snapshot_units The #unit_system used in the snapshots
  *
@@ -717,7 +716,7 @@ void read_ic_single(const char* fileName,
  * Calls #error() if an error occurs.
  *
  */
-void write_output_single(struct engine* e, const char* baseName,
+void write_output_single(struct engine* e,
                          const struct unit_system* internal_units,
                          const struct unit_system* snapshot_units) {
 
@@ -777,22 +776,18 @@ void write_output_single(struct engine* e, const char* baseName,
 
   /* File name */
   char fileName[FILENAME_BUFFER_SIZE];
-  if (e->snapshot_int_time_label_on)
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%06i.hdf5", baseName,
-             (int)round(e->time));
-  else if (e->snapshot_invoke_stf) {
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->stf_output_count);
-  } else
-    snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName,
-             e->snapshot_output_count);
+  char xmfFileName[FILENAME_BUFFER_SIZE];
+  io_get_snapshot_filename(fileName, xmfFileName, e->snapshot_int_time_label_on,
+                           e->snapshot_invoke_stf, e->time, e->stf_output_count,
+                           e->snapshot_output_count, e->snapshot_subdir,
+                           e->snapshot_base_name);
 
   /* First time, we need to create the XMF file */
-  if (e->snapshot_output_count == 0) xmf_create_file(baseName);
+  if (e->snapshot_output_count == 0) xmf_create_file(xmfFileName);
 
   /* Prepare the XMF file for the new entry */
   FILE* xmfFile = 0;
-  xmfFile = xmf_prepare_file(baseName);
+  xmfFile = xmf_prepare_file(xmfFileName);
 
   /* Write the part corresponding to this specific output */
   xmf_write_outputheader(xmfFile, fileName, e->time);
diff --git a/src/single_io.h b/src/single_io.h
index c341fda920e25d9c109e85e6b0967355f09fa6be..24e6bd4e3d0d4181a8e73ae838931256e5687f8d 100644
--- a/src/single_io.h
+++ b/src/single_io.h
@@ -40,7 +40,7 @@ void read_ic_single(const char* fileName,
                     int with_cosmology, int cleanup_h, int cleanup_sqrt_a,
                     double h, double a, int nr_threads, int dry_run);
 
-void write_output_single(struct engine* e, const char* baseName,
+void write_output_single(struct engine* e,
                          const struct unit_system* internal_units,
                          const struct unit_system* snapshot_units);
 
diff --git a/src/xmf.c b/src/xmf.c
index d3d88627b8fe0c0e40df53c6eb79960ef82f1519..dcba990005c71f9da885d61575189910953d1af5 100644
--- a/src/xmf.c
+++ b/src/xmf.c
@@ -51,15 +51,13 @@ static const char* xmf_basename(const char* hdfFileName) {
 /**
  * @brief Prepare the XMF file corresponding to a snapshot.
  *
- * @param baseName The common part of the file name.
+ * @param fileName The name of the file.
  */
-FILE* xmf_prepare_file(const char* baseName) {
+FILE* xmf_prepare_file(const char* fileName) {
   char buffer[1024];
 
-  char fileName[FILENAME_BUFFER_SIZE];
   char tempFileName[FILENAME_BUFFER_SIZE];
-  snprintf(fileName, FILENAME_BUFFER_SIZE, "%s.xmf", baseName);
-  snprintf(tempFileName, FILENAME_BUFFER_SIZE, "%s_temp.xmf", baseName);
+  snprintf(tempFileName, FILENAME_BUFFER_SIZE, "%s.temp", fileName);
   FILE* xmfFile = fopen(fileName, "r");
   FILE* tempFile = fopen(tempFileName, "w");
 
@@ -101,11 +99,11 @@ FILE* xmf_prepare_file(const char* baseName) {
  *
  * @todo Exploit the XML nature of the XMF format to write a proper XML writer
  * and simplify all the XMF-related stuff.
+ *
+ * @param fileName The name of the file.
  */
-void xmf_create_file(const char* baseName) {
+void xmf_create_file(const char* fileName) {
 
-  char fileName[FILENAME_BUFFER_SIZE];
-  snprintf(fileName, FILENAME_BUFFER_SIZE, "%s.xmf", baseName);
   FILE* xmfFile = fopen(fileName, "w");
   if (xmfFile == NULL) error("Unable to create XMF file.");
 
@@ -134,7 +132,8 @@ void xmf_create_file(const char* baseName) {
  * @param hdfFileName The name of the HDF5 file corresponding to this output.
  * @param time The current simulation time.
  */
-void xmf_write_outputheader(FILE* xmfFile, char* hdfFileName, float time) {
+void xmf_write_outputheader(FILE* xmfFile, const char* hdfFileName,
+                            float time) {
   /* Write end of file */
 
   fprintf(xmfFile, "<!-- XMF description for file: %s -->\n", hdfFileName);
@@ -171,7 +170,7 @@ void xmf_write_outputfooter(FILE* xmfFile, int output, float time) {
  * @param N The number of particles to write.
  * @param ptype The particle type we are writing.
  */
-void xmf_write_groupheader(FILE* xmfFile, char* hdfFileName, size_t N,
+void xmf_write_groupheader(FILE* xmfFile, const char* hdfFileName, size_t N,
                            enum part_type ptype) {
 
   fprintf(xmfFile, "\n<Grid Name=\"%s\" GridType=\"Uniform\">\n",
diff --git a/src/xmf.h b/src/xmf.h
index bd2781685f8d1f96daf6e5bfeb45a2bf645fca6e..e742ec8043ef815357ae4a708ed9afdd30ec474e 100644
--- a/src/xmf.h
+++ b/src/xmf.h
@@ -26,11 +26,11 @@
 #include "common_io.h"
 #include "part_type.h"
 
-void xmf_create_file(const char* baseName);
-FILE* xmf_prepare_file(const char* baseName);
-void xmf_write_outputheader(FILE* xmfFile, char* hdfFileName, float time);
+void xmf_create_file(const char* fileName);
+FILE* xmf_prepare_file(const char* fileName);
+void xmf_write_outputheader(FILE* xmfFile, const char* hdfFileName, float time);
 void xmf_write_outputfooter(FILE* xmfFile, int outputCount, float time);
-void xmf_write_groupheader(FILE* xmfFile, char* hdfFileName, size_t N,
+void xmf_write_groupheader(FILE* xmfFile, const char* hdfFileName, size_t N,
                            enum part_type ptype);
 void xmf_write_groupfooter(FILE* xmfFile, enum part_type ptype);
 void xmf_write_line(FILE* xmfFile, const char* fileName,