+#ifdef HAVE_CLONEFILE
+zip_int64_t
+static create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset)
+{
+ char *temp;
+ FILE *tfp;
+
+ if (offset > ZIP_OFF_MAX) {
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG);
+ return -1;
+ }
+
+ if ((temp=(char *)malloc(strlen(ctx->fname)+8)) == NULL) {
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
+ return -1;
+ }
+ sprintf(temp, "%s.XXXXXX", ctx->fname);
+
+ if (mktemp(temp) == NULL) {
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
+ free(temp);
+ return -1;
+ }
+
+ if (clonefile(ctx->fname, temp, 0) < 0) {
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
+ free(temp);
+ return -1;
+ }
+ if ((tfp=fopen(temp, "r+b")) == NULL) {
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
+ (void)remove(temp);
+ free(temp);
+ return -1;
+ }
+ if (ftruncate(fileno(tfp), (off_t)offset) < 0
+ || fseeko(tfp, (off_t)offset, SEEK_SET) < 0) {
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
+ (void)remove(temp);
+ free(temp);
+ return -1;
+ }
+
+ ctx->fout = tfp;
+ ctx->tmpname = temp;
+
+ return 0;
+}
+#endif
+