/** * Create a writable mimic directory based on reference directory. * * The mimic directory is a tmpfs populated with bind mounts to the (possibly * read only) directories in the reference directory. While all the read-only * content stays read-only the actual mimic directory is writable so additional * content can be placed there. * * Flags are forwarded to sc_quirk_mkdir_bind() **/ static void sc_quirk_create_writable_mimic(const char *mimic_dir, const char *ref_dir, unsigned flags) { debug("creating writable mimic directory %s based on %s", mimic_dir, ref_dir); sc_quirk_setup_tmpfs(mimic_dir); // Now copy the ownership and permissions of the mimicked directory struct stat stat_buf; if (stat(ref_dir, &stat_buf) < 0) { die("cannot stat %s", ref_dir); } if (chown(mimic_dir, stat_buf.st_uid, stat_buf.st_gid) < 0) { die("cannot chown for %s", mimic_dir); } if (chmod(mimic_dir, stat_buf.st_mode) < 0) { die("cannot chmod for %s", mimic_dir); } debug("bind-mounting all the files from the reference directory"); DIR *dirp SC_CLEANUP(sc_cleanup_closedir) = NULL; dirp = opendir(ref_dir); if (dirp == NULL) { die("cannot open reference directory %s", ref_dir); } struct dirent *entryp = NULL; do { char src_name[PATH_MAX * 2] = { 0 }; char dest_name[PATH_MAX * 2] = { 0 }; // Set errno to zero, if readdir fails it will not only return null but // set errno to a non-zero value. This is how we can differentiate // end-of-directory from an actual error. errno = 0; entryp = readdir(dirp); if (entryp == NULL && errno != 0) { die("cannot read another directory entry"); } if (entryp == NULL) { break; } if (strcmp(entryp->d_name, ".") == 0 || strcmp(entryp->d_name, "..") == 0) { continue; } if (entryp->d_type != DT_DIR && entryp->d_type != DT_REG) { die("unsupported entry type of file %s (%d)", entryp->d_name, entryp->d_type); } sc_must_snprintf(src_name, sizeof src_name, "%s/%s", ref_dir, entryp->d_name); sc_must_snprintf(dest_name, sizeof dest_name, "%s/%s", mimic_dir, entryp->d_name); sc_quirk_mkdir_bind(src_name, dest_name, flags); } while (entryp != NULL); }
/** * Create a writable mimic directory based on reference directory. * * The mimic directory is a tmpfs populated with bind mounts to the (possibly * read only) directories in the reference directory. While all the read-only * content stays read-only the actual mimic directory is writable so additional * content can be placed there. * * Flags are forwarded to sc_quirk_mkdir_bind() **/ static void sc_quirk_create_writable_mimic(const char *mimic_dir, const char *ref_dir, unsigned flags) { debug("creating writable mimic directory %s based on %s", mimic_dir, ref_dir); sc_quirk_setup_tmpfs(mimic_dir); debug("bind-mounting all the files from the reference directory"); DIR *dirp __attribute__ ((cleanup(sc_cleanup_closedir))) = NULL; dirp = opendir(ref_dir); if (dirp == NULL) { die("cannot open reference directory %s", ref_dir); } struct dirent *entryp = NULL; do { char src_name[PATH_MAX * 2]; char dest_name[PATH_MAX * 2]; // Set errno to zero, if readdir fails it will not only return null but // set errno to a non-zero value. This is how we can differentiate // end-of-directory from an actual error. errno = 0; entryp = readdir(dirp); if (entryp == NULL && errno != 0) { die("cannot read another directory entry"); } if (entryp == NULL) { break; } if (strcmp(entryp->d_name, ".") == 0 || strcmp(entryp->d_name, "..") == 0) { continue; } if (entryp->d_type != DT_DIR && entryp->d_type != DT_REG) { die("unsupported entry type of file %s (%d)", entryp->d_name, entryp->d_type); } must_snprintf(src_name, sizeof src_name, "%s/%s", ref_dir, entryp->d_name); must_snprintf(dest_name, sizeof dest_name, "%s/%s", mimic_dir, entryp->d_name); sc_quirk_mkdir_bind(src_name, dest_name, flags); } while (entryp != NULL); }