Backport.
From 73800fc0cd81a735764f79b7f3f957d8a71eb02c Mon Sep 17 00:00:00 2001
From: "R. Bernstein" <rocky@gnu.org>
Date: Tue, 28 Nov 2017 23:39:14 -0500
Subject: [PATCH 7/20] WIP: deal with memory leaks from cdio_lists

TODO:
   * create function for dirlist free; is:
      _cdio_list_free (dirlist, true, free);
   * create function for statbuf free; is:
     _cdio_list_free (entlist, true, (CdioDataFree_t) iso9660_stat_free);

   * Add targets to run valgrind to look for memory leaks
   * Fix remaining memory leaks
---
 configure.ac               |   2 +-
 example/extract.c          |   4 +-
 example/isofuzzy.c         |  26 +++---
 example/isolist.c          |  29 +++----
 example/udf1.c             |   2 +-
 example/udffile.c          |  44 +++++-----
 include/cdio++/iso9660.hpp | 174 ++++++++++++++++++-------------------
 include/cdio/ds.h          |   5 +-
 include/cdio/types.h       |   4 +
 lib/cdio++/iso9660.cpp     | 106 +++++++++++-----------
 lib/driver/_cdio_stream.c  |   2 +-
 lib/driver/ds.c            |  11 +--
 lib/driver/image/nrg.c     |   5 +-
 lib/iso9660/iso9660_fs.c   |  29 ++++---
 src/cd-info.c              |   8 +-
 src/iso-info.c             |  28 +++---
 test/testisocd2.c          |  34 +++++---
 17 files changed, 263 insertions(+), 250 deletions(-)

Index: libcdio-0.94/configure.ac
===================================================================
--- libcdio-0.94.orig/configure.ac
+++ libcdio-0.94/configure.ac
@@ -190,7 +190,7 @@ AC_DEFINE(LIBCDIO_CONFIG_H, 1,
 dnl headers
 
 AC_HEADER_STDC
-AC_CHECK_HEADERS(errno.h fcntl.h glob.h limits.h pwd.h stdbool.h)
+AC_CHECK_HEADERS(alloca.h errno.h fcntl.h glob.h limits.h pwd.h stdbool.h)
 AC_CHECK_HEADERS(stdarg.h stdbool.h stdio.h sys/cdio.h sys/param.h \
 		 sys/time.h sys/timeb.h sys/utsname.h)
 
Index: libcdio-0.94/example/extract.c
===================================================================
--- libcdio-0.94.orig/example/extract.c
+++ libcdio-0.94/example/extract.c
@@ -1,6 +1,6 @@
 /*
   Copyright (C) 2012 Pete Batard <pete@akeo.ie>
-  Based on samples copyright (c) 2003-2011 Rocky Bernstein <rocky@gnu.org>
+  Based on samples copyright (c) 2003-2011, 2017 Rocky Bernstein <rocky@gnu.org>
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -236,7 +236,7 @@ static int iso_extract_files(iso9660_t*
 out:
   if (fd != NULL)
     fclose(fd);
-  _cdio_list_free(p_entlist, true);
+  _cdio_list_free(p_entlist, true, (CdioDataFree_t) iso9660_stat_free);
   return r;
 }
 
Index: libcdio-0.94/example/isofuzzy.c
===================================================================
--- libcdio-0.94.orig/example/isofuzzy.c
+++ libcdio-0.94/example/isofuzzy.c
@@ -1,6 +1,6 @@
 /*
-  Copyright (C) 2005, 2008, 2009 Rocky Bernstein <rocky@gnu.org>
-  
+  Copyright (C) 2005, 2008, 2009, 2017 Rocky Bernstein <rocky@gnu.org>
+
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
@@ -55,39 +55,39 @@
 int
 main(int argc, const char *argv[])
 {
-  CdioList_t *entlist;
+  CdioList_t *p_entlist;
   CdioListNode_t *entnode;
   char const *psz_fname;
   iso9660_t *p_iso;
 
-  if (argc > 1) 
+  if (argc > 1)
     psz_fname = argv[1];
-  else 
+  else
     psz_fname = ISO9660_IMAGE;
 
   p_iso = iso9660_open_fuzzy (psz_fname, 5);
-  
+
   if (NULL == p_iso) {
-    fprintf(stderr, "-- Sorry, could not find an ISO 9660 image from %s\n", 
+    fprintf(stderr, "-- Sorry, could not find an ISO 9660 image from %s\n",
 	    psz_fname);
     return 1;
   }
 
-  entlist = iso9660_ifs_readdir (p_iso, "/");
-    
+  p_entlist = iso9660_ifs_readdir (p_iso, "/");
+
   /* Iterate over the list of nodes that iso9660_ifs_readdir gives  */
 
-  if (entlist) {
-    _CDIO_LIST_FOREACH (entnode, entlist)
+  if (p_entlist) {
+    _CDIO_LIST_FOREACH (entnode, p_entlist)
     {
       char filename[4096];
-      iso9660_stat_t *p_statbuf = 
+      iso9660_stat_t *p_statbuf =
 	(iso9660_stat_t *) _cdio_list_node_data (entnode);
       iso9660_name_translate(p_statbuf->filename, filename);
       printf ("-- /%s\n", filename);
     }
 
-    _cdio_list_free (entlist, true);
+    _cdio_list_free(p_entlist, true, (CdioDataFree_t) iso9660_stat_free);
   }
 
   iso9660_close(p_iso);
Index: libcdio-0.94/example/isolist.c
===================================================================
--- libcdio-0.94.orig/example/isolist.c
+++ libcdio-0.94/example/isolist.c
@@ -1,7 +1,7 @@
 /*
   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011
    Rocky Bernstein <rocky@gnu.org>
-  
+
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
@@ -58,7 +58,7 @@
     printf(title ": %s\n", psz_str);	  \
   }					  \
   free(psz_str);			  \
-  psz_str = NULL;			  
+  psz_str = NULL;
 
 
 int
@@ -70,15 +70,15 @@ main(int argc, const char *argv[])
   iso9660_t *p_iso;
   const char *psz_path="/";
 
-  if (argc > 1) 
+  if (argc > 1)
     psz_fname = argv[1];
-  else 
+  else
     psz_fname = ISO9660_IMAGE;
 
   p_iso = iso9660_open (psz_fname);
-  
+
   if (NULL == p_iso) {
-    fprintf(stderr, "Sorry, couldn't open %s as an ISO-9660 image\n", 
+    fprintf(stderr, "Sorry, couldn't open %s as an ISO-9660 image\n",
 	    psz_fname);
     return 1;
   }
@@ -93,28 +93,27 @@ main(int argc, const char *argv[])
     print_vd_info("Volume     ", iso9660_ifs_get_volume_id);
     print_vd_info("Volume Set ", iso9660_ifs_get_volumeset_id);
   }
-    
+
   p_entlist = iso9660_ifs_readdir (p_iso, psz_path);
-    
+
   /* Iterate over the list of nodes that iso9660_ifs_readdir gives  */
-  
+
   if (p_entlist) {
     _CDIO_LIST_FOREACH (p_entnode, p_entlist)
     {
       char filename[4096];
-      iso9660_stat_t *p_statbuf = 
+      iso9660_stat_t *p_statbuf =
 	(iso9660_stat_t *) _cdio_list_node_data (p_entnode);
       iso9660_name_translate(p_statbuf->filename, filename);
-      printf ("%s [LSN %6d] %8u %s%s\n", 
+      printf ("%s [LSN %6d] %8u %s%s\n",
 	      _STAT_DIR == p_statbuf->type ? "d" : "-",
 	      p_statbuf->lsn, p_statbuf->size, psz_path, filename);
     }
-    
-    _cdio_list_free (p_entlist, true);
+
+    _cdio_list_free(p_entlist, true, (CdioDataFree_t) iso9660_stat_free);
   }
-  
+
 
   iso9660_close(p_iso);
   return 0;
 }
-
Index: libcdio-0.94/example/udf1.c
===================================================================
--- libcdio-0.94.orig/example/udf1.c
+++ libcdio-0.94/example/udf1.c
@@ -21,7 +21,7 @@
 
 /* This is the UDF image. */
 #define UDF_IMAGE_PATH "../"
-#define UDF_IMAGE "/src2/cd-images/udf/UDF102ISO.iso"
+#define UDF_IMAGE "../test/data/udf102.iso"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
Index: libcdio-0.94/example/udffile.c
===================================================================
--- libcdio-0.94.orig/example/udffile.c
+++ libcdio-0.94/example/udffile.c
@@ -1,7 +1,7 @@
 /*
-  Copyright (C) 2005, 2006, 2008, 2009, 2010, 2011
+  Copyright (C) 2005, 2006, 2008-2011, 2017
    Rocky Bernstein <rocky@gnu.org>
-  
+
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
@@ -18,7 +18,7 @@
 
 /* Simple program to show using libudf to extract a file.
 
-   This program can be compiled with either a C or C++ compiler. In 
+   This program can be compiled with either a C or C++ compiler. In
    the distribution we prefer C++ just to make sure we haven't broken
    things on the C++ side.
  */
@@ -32,7 +32,7 @@
 
 /* This is the UDF image. */
 #define UDF_IMAGE_PATH "../"
-#define UDF_IMAGE "../test/udf102.iso"
+#define UDF_IMAGE "../test/data/udf102.iso"
 #define UDF_FILENAME "/COPYING"
 #define LOCAL_FILENAME "copying"
 
@@ -71,48 +71,52 @@ main(int argc, const char *argv[])
   char const *psz_udf_fname;
   char const *psz_local_fname;
 
-  if (argc > 1) 
+  if (argc > 1)
     psz_udf_image = argv[1];
-  else 
+  else
     psz_udf_image = UDF_IMAGE;
 
-  if (argc > 2) 
+  if (argc > 2)
     psz_udf_fname = argv[2];
-  else 
+  else
     psz_udf_fname = UDF_FILENAME;
 
-  if (argc > 3) 
+  if (argc > 3)
     psz_local_fname = argv[3];
-  else 
+  else
     psz_local_fname = LOCAL_FILENAME;
 
 
   p_udf = udf_open (psz_udf_image);
-  
+
   if (NULL == p_udf) {
-    fprintf(stderr, "Sorry, couldn't open %s as something using UDF\n", 
+    fprintf(stderr, "Sorry, couldn't open %s as something using UDF\n",
 	    psz_udf_image);
     return 1;
   } else {
     udf_dirent_t *p_udf_root = udf_get_root(p_udf, true, 0);
     udf_dirent_t *p_udf_file = NULL;
     if (NULL == p_udf_root) {
-      fprintf(stderr, "Sorry, couldn't find / in %s\n", 
+      fprintf(stderr, "Sorry, couldn't find / in %s\n",
 	      psz_udf_image);
+      udf_close(p_udf);
       return 1;
     }
-    
+
     p_udf_file = udf_fopen(p_udf_root, psz_udf_fname);
     if (!p_udf_file) {
-      fprintf(stderr, "Sorry, couldn't find %s in %s\n", 
+      fprintf(stderr, "Sorry, couldn't find %s in %s\n",
 	      psz_udf_fname, psz_udf_image);
+      udf_close(p_udf);
       return 2;
-      
+
     }
 
     if (!(p_outfd = fopen (psz_local_fname, "wb")))
       {
 	perror ("fopen()");
+	udf_close(p_udf);
+	udf_dirent_free(p_udf_file);
 	return 3;
     }
 
@@ -139,6 +143,7 @@ main(int argc, const char *argv[])
       }
 
       fflush (p_outfd);
+      udf_dirent_free(p_udf_file);
       udf_dirent_free(p_udf_root);
       udf_close(p_udf);
       /* Make sure the file size has the exact same byte size. Without the
@@ -146,12 +151,11 @@ main(int argc, const char *argv[])
       */
       if (ftruncate (fileno (p_outfd), i_file_length))
 	perror ("ftruncate()");
-      
-      printf("Extraction of file '%s' from %s successful.\n", 
+
+      printf("Extraction of file '%s' from %s successful.\n",
 	     psz_local_fname, psz_udf_image);
-      
+
       return 0;
     }
   }
 }
-
Index: libcdio-0.94/include/cdio++/iso9660.hpp
===================================================================
--- libcdio-0.94.orig/include/cdio++/iso9660.hpp
+++ libcdio-0.94/include/cdio++/iso9660.hpp
@@ -48,68 +48,68 @@ public:
     {
       memset(&pvd, 0, sizeof(pvd));
     }
-    
+
     PVD(iso9660_pvd_t *p_new_pvd)
-    { 
+    {
       memcpy(&pvd, p_new_pvd, sizeof(pvd));
     };
 
     /*!
       Return the PVD's application ID.
-      NULL is returned if there is some problem in getting this. 
+      NULL is returned if there is some problem in getting this.
     */
     char * get_application_id();
-    
+
     int get_pvd_block_size();
-    
+
     /*!
       Return the PVD's preparer ID.
-      NULL is returned if there is some problem in getting this. 
+      NULL is returned if there is some problem in getting this.
     */
     char * get_preparer_id();
-    
+
     /*!
       Return the PVD's publisher ID.
-      NULL is returned if there is some problem in getting this. 
+      NULL is returned if there is some problem in getting this.
     */
     char * get_publisher_id();
-    
+
     const char *get_pvd_id();
-    
+
     int get_pvd_space_size();
-    
+
     uint8_t get_pvd_type();
-    
+
     /*! Return the primary volume id version number (of pvd).
-      If there is an error 0 is returned. 
+      If there is an error 0 is returned.
     */
     int get_pvd_version();
-    
+
     /*! Return the LSN of the root directory for pvd.
-      If there is an error CDIO_INVALID_LSN is returned. 
+      If there is an error CDIO_INVALID_LSN is returned.
     */
     lsn_t get_root_lsn();
-  
+
     /*!
       Return the PVD's system ID.
-      NULL is returned if there is some problem in getting this. 
+      NULL is returned if there is some problem in getting this.
     */
     char * get_system_id();
-    
+
     /*!
       Return the PVD's volume ID.
-      NULL is returned if there is some problem in getting this. 
+      NULL is returned if there is some problem in getting this.
     */
     char * get_volume_id();
-    
+
     /*!
       Return the PVD's volumeset ID.
-      NULL is returned if there is some problem in getting this. 
+      NULL is returned if there is some problem in getting this.
     */
     char * get_volumeset_id();
-    
+
   };
-    
+
   class Stat  // ISO 9660 file information
   {
   public:
@@ -118,37 +118,37 @@ public:
     typedef vector< ISO9660::Stat *> stat_vector_t;
 
     Stat(iso9660_stat_t *p_new_stat)
-    { 
+    {
       p_stat = p_new_stat;
     };
 
-    Stat(const Stat& copy_in) 
+    Stat(const Stat& copy_in)
     {
       free(p_stat);
-      p_stat = (iso9660_stat_t *) 
-        calloc( 1, sizeof(iso9660_stat_t) 
+      p_stat = (iso9660_stat_t *)
+        calloc( 1, sizeof(iso9660_stat_t)
                 + strlen(copy_in.p_stat->filename)+1 );
       p_stat = copy_in.p_stat;
     }
-      
-    const Stat& operator= (const Stat& right) 
+
+    const Stat& operator= (const Stat& right)
     {
       free(p_stat);
       this->p_stat = right.p_stat;
       return right;
     }
-    
-    ~Stat() 
+
+    ~Stat()
     {
       iso9660_stat_free(p_stat);
       p_stat = NULL;
     }
-    
+
   };
 
 #ifdef FS
  #undef FS
-#endif  
+#endif
   class FS : public CdioDevice // ISO 9660 Filesystem on a CD or CD-image
   {
   public:
@@ -158,7 +158,7 @@ public:
     /*!
       Given a directory pointer, find the filesystem entry that contains
       lsn and return information about it.
-      
+
       @return Stat * of entry if we found lsn, or NULL otherwise.
       Caller must release returned object using delete when done.
     */
@@ -170,8 +170,8 @@ public:
     PVD *read_pvd ();
 
     /*!
-      Read the Super block of an ISO 9660 image. This is the 
-      Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume 
+      Read the Super block of an ISO 9660 image. This is the
+      Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume
       Descriptor if (Joliet) extensions are acceptable.
     */
     bool read_superblock (iso_extension_mask_t iso_extension_mask);
@@ -186,29 +186,29 @@ public:
     /*!
       Return file status for path name psz_path. NULL is returned on
       error.
-      
+
       If translate is true, version numbers in the ISO 9660 name are
       dropped, i.e. ;1 is removed and if level 1 ISO-9660 names are
       lowercased.
-      
+
       Mode2 is used only if translate is true and is a hack that
       really should go away in libcdio sometime. If set use mode 2
       reading, otherwise use mode 1 reading.
-      
+
       @return file status object for psz_path. NULL is returned on
       error. Caller must release returned object using delete when done.
     */
     Stat *
     stat (const char psz_path[], bool b_translate=false, bool b_mode2=false)
     {
-      if (b_translate) 
-        return new Stat(iso9660_fs_stat_translate (p_cdio, psz_path, 
+      if (b_translate)
+        return new Stat(iso9660_fs_stat_translate (p_cdio, psz_path,
                                                             b_mode2));
-      else 
+      else
         return new Stat(iso9660_fs_stat (p_cdio, psz_path));
     }
   };
-  
+
   class IFS  // ISO 9660 filesystem image
   {
   public:
@@ -216,20 +216,20 @@ public:
     typedef vector< ISO9660::Stat *> stat_vector_t;
 
     IFS()
-    { 
-      p_iso9660=NULL; 
+    {
+      p_iso9660=NULL;
     };
 
-    ~IFS() 
-    { 
-      iso9660_close(p_iso9660); 
+    ~IFS()
+    {
+      iso9660_close(p_iso9660);
       p_iso9660 = (iso9660_t *) NULL;
     };
-    
+
     /*! Close previously opened ISO 9660 image and free resources
       associated with the image. Call this when done using using an ISO
       9660 image.
-      
+
       @return true is unconditionally returned. If there was an error
       false would be returned.
     */
@@ -238,45 +238,45 @@ public:
     /*!
       Given a directory pointer, find the filesystem entry that contains
       lsn and return information about it.
-      
+
       Returns Stat*  of entry if we found lsn, or NULL otherwise.
       Caller must release returned object using delete when done.
     */
     Stat *find_lsn(lsn_t i_lsn);
 
-    /*!  
+    /*!
       Get the application ID.  psz_app_id is set to NULL if there
       is some problem in getting this and false is returned.
     */
-    bool get_application_id(/*out*/ char * &psz_app_id) 
+    bool get_application_id(/*out*/ char * &psz_app_id)
     {
       return iso9660_ifs_get_application_id(p_iso9660, &psz_app_id);
     }
-    
-    /*!  
-      Return the Joliet level recognized. 
+
+    /*!
+      Return the Joliet level recognized.
     */
     uint8_t get_joliet_level();
-    
-    /*!  
+
+    /*!
       Get the preparer ID.  psz_preparer_id is set to NULL if there
       is some problem in getting this and false is returned.
     */
-    bool get_preparer_id(/*out*/ char * &psz_preparer_id) 
+    bool get_preparer_id(/*out*/ char * &psz_preparer_id)
     {
       return iso9660_ifs_get_preparer_id(p_iso9660, &psz_preparer_id);
     }
 
-    /*!  
+    /*!
       Get the publisher ID.  psz_publisher_id is set to NULL if there
       is some problem in getting this and false is returned.
     */
-    bool get_publisher_id(/*out*/ char * &psz_publisher_id) 
+    bool get_publisher_id(/*out*/ char * &psz_publisher_id)
     {
       return iso9660_ifs_get_publisher_id(p_iso9660, &psz_publisher_id);
     }
-    
-    /*!  
+
+    /*!
       Get the system ID.  psz_system_id is set to NULL if there
       is some problem in getting this and false is returned.
     */
@@ -284,21 +284,21 @@ public:
     {
       return iso9660_ifs_get_system_id(p_iso9660, &psz_system_id);
     }
-    
+
     /*! Return the volume ID in the PVD. psz_volume_id is set to
       NULL if there is some problem in getting this and false is
       returned.
     */
-    bool get_volume_id(/*out*/ char * &psz_volume_id) 
+    bool get_volume_id(/*out*/ char * &psz_volume_id)
     {
       return iso9660_ifs_get_volume_id(p_iso9660, &psz_volume_id);
     }
-    
+
     /*! Return the volumeset ID in the PVD. psz_volumeset_id is set to
       NULL if there is some problem in getting this and false is
       returned.
     */
-    bool get_volumeset_id(/*out*/ char * &psz_volumeset_id) 
+    bool get_volumeset_id(/*out*/ char * &psz_volumeset_id)
     {
       return iso9660_ifs_get_volumeset_id(p_iso9660, &psz_volumeset_id);
     }
@@ -312,16 +312,16 @@ public:
       have a mode. NULL is returned on error. An open routine should be
       called before using any read routine. If device object was
       previously opened it is closed first.
-      
+
       @param psz_path location of ISO 9660 image
       @param iso_extension_mask the kinds of ISO 9660 extensions will be
       considered on access.
-      
+
       @return true if open succeeded or false if error.
-      
+
       @see open_fuzzy
     */
-    bool open(const char *psz_path, 
+    bool open(const char *psz_path,
               iso_extension_mask_t iso_extension_mask=ISO_EXTENSION_NONE)
     {
       if (p_iso9660) iso9660_close(p_iso9660);
@@ -334,10 +334,10 @@ public:
       checks. This may be useful when trying to read an ISO 9660 image
       contained in a file format that libiso9660 doesn't know natively
       (or knows imperfectly.)
-      
+
       Maybe in the future we will have a mode. NULL is returned on
       error.
-      
+
       @see open
     */
     bool open_fuzzy (const char *psz_path,
@@ -349,7 +349,7 @@ public:
       PVD object is returned if read, and NULL if there was an error.
     */
     PVD *read_pvd ();
-  
+
     /*!
       Read the Super block of an ISO 9660 image but determine framesize
       and datastart and a possible additional offset. Generally here we are
@@ -370,7 +370,7 @@ public:
 
       @see read_superblock
     */
-    bool 
+    bool
     read_superblock_fuzzy (iso_extension_mask_t iso_extension_mask
                            =ISO_EXTENSION_NONE,
                            uint16_t i_fuzz=20);
@@ -379,18 +379,18 @@ public:
       pointers for the files inside that directory. The caller must free
       the returned result.
     */
-    bool readdir (const char psz_path[], stat_vector_t& stat_vector) 
+    bool readdir (const char psz_path[], stat_vector_t& stat_vector)
     {
       CdioList_t *p_stat_list = iso9660_ifs_readdir (p_iso9660, psz_path);
-      
+
       if (p_stat_list) {
         CdioListNode_t *p_entnode;
         _CDIO_LIST_FOREACH (p_entnode, p_stat_list) {
-          iso9660_stat_t *p_statbuf = 
+          iso9660_stat_t *p_statbuf =
             (iso9660_stat_t *) _cdio_list_node_data (p_entnode);
           stat_vector.push_back(new ISO9660::Stat(p_statbuf));
         }
-        _cdio_list_free (p_stat_list, false);
+        _cdio_list_free (p_stat_list, false, (CdioDataFree_t) iso9660_stat_free);
         return true;
       } else {
         return false;
@@ -400,25 +400,25 @@ public:
     /*!
       Seek to a position and then read n bytes. Size read is returned.
     */
-    long int 
-    seek_read (void *ptr, lsn_t start, long int i_size=1) 
+    long int
+    seek_read (void *ptr, lsn_t start, long int i_size=1)
     {
       return iso9660_iso_seek_read (p_iso9660, ptr, start, i_size);
     }
-    
-    /*!  
+
+    /*!
       Return file status for pathname. NULL is returned on error.
       Caller must release returned object using delete when done.
     */
     Stat *
-    stat (const char psz_path[], bool b_translate=false) 
+    stat (const char psz_path[], bool b_translate=false)
     {
-      if (b_translate) 
+      if (b_translate)
         return new Stat(iso9660_ifs_stat_translate (p_iso9660, psz_path));
-      else 
+      else
         return new Stat(iso9660_ifs_stat (p_iso9660, psz_path));
     }
-    
+
   private:
     iso9660_t *p_iso9660;
   };
Index: libcdio-0.94/include/cdio/ds.h
===================================================================
--- libcdio-0.94.orig/include/cdio/ds.h
+++ libcdio-0.94/include/cdio/ds.h
@@ -43,7 +43,7 @@ extern "C" {
 /** methods */
 CdioList_t *_cdio_list_new (void);
 
-void _cdio_list_free (CdioList_t *p_list, int free_data);
+void _cdio_list_free (CdioList_t *p_list, int free_data, CdioDataFree_t free_fn);
 
 unsigned _cdio_list_length (const CdioList_t *list);
 
@@ -69,7 +69,8 @@ CdioListNode_t *_cdio_list_end (CdioList
 
 CdioListNode_t *_cdio_list_node_next (CdioListNode_t *p_node);
 
-void _cdio_list_node_free (CdioListNode_t *p_node, int i_free_data);
+  void _cdio_list_node_free (CdioListNode_t *p_node, int i_free_data,
+                             CdioDataFree_t free_fn);
 
 void *_cdio_list_node_data (CdioListNode_t *p_node);
 
Index: libcdio-0.94/include/cdio/types.h
===================================================================
--- libcdio-0.94.orig/include/cdio/types.h
+++ libcdio-0.94/include/cdio/types.h
@@ -335,6 +335,10 @@ typedef uint8_t ubyte;
   CDIO_TRACK_FLAG_SCMS =                 0x10   /**< SCMS (5.29.2.7) */
 } cdio_track_flag;
 
+
+/* Note that this matches the free() prototype.*/
+typedef void (*CdioDataFree_t)(void *ptr);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: libcdio-0.94/lib/cdio++/iso9660.cpp
===================================================================
--- libcdio-0.94.orig/lib/cdio++/iso9660.cpp
+++ libcdio-0.94/lib/cdio++/iso9660.cpp
@@ -29,12 +29,12 @@
 /*!
   Given a directory pointer, find the filesystem entry that contains
   lsn and return information about it.
-  
+
   @return Stat * of entry if we found lsn, or NULL otherwise.
   Caller must release returned object using delete when done.
 */
 ISO9660::Stat *
-ISO9660::FS::find_lsn(lsn_t i_lsn) 
+ISO9660::FS::find_lsn(lsn_t i_lsn)
 {
   return new Stat(iso9660_find_fs_lsn(p_cdio, i_lsn));
 }
@@ -55,12 +55,12 @@ ISO9660::FS::read_pvd ()
 }
 
 /*!
-  Read the Super block of an ISO 9660 image. This is the 
-  Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume 
+  Read the Super block of an ISO 9660 image. This is the
+  Primary Volume Descriptor (PVD) and perhaps a Supplemental Volume
   Descriptor if (Joliet) extensions are acceptable.
 */
-bool 
-ISO9660::FS::read_superblock (iso_extension_mask_t iso_extension_mask) 
+bool
+ISO9660::FS::read_superblock (iso_extension_mask_t iso_extension_mask)
 {
   return iso9660_fs_read_superblock (p_cdio, iso_extension_mask);
 }
@@ -69,20 +69,20 @@ ISO9660::FS::read_superblock (iso_extens
   pointers for the files inside that directory. The caller must free the
   returned result.
 */
-bool 
+bool
 ISO9660::FS::readdir (const char psz_path[], stat_vector_t& stat_vector,
 		      bool b_mode2)
 {
-  CdioList_t * p_stat_list = iso9660_fs_readdir (p_cdio, psz_path, 
+  CdioList_t * p_stat_list = iso9660_fs_readdir (p_cdio, psz_path,
 						 b_mode2);
   if (p_stat_list) {
     CdioListNode_t *p_entnode;
     _CDIO_LIST_FOREACH (p_entnode, p_stat_list) {
-      iso9660_stat_t *p_statbuf = 
+      iso9660_stat_t *p_statbuf =
 	(iso9660_stat_t *) _cdio_list_node_data (p_entnode);
       stat_vector.push_back(new ISO9660::Stat(p_statbuf));
     }
-    _cdio_list_free (p_stat_list, false);
+    _cdio_list_free (p_stat_list, false, (CdioDataFree_t) iso9660_stat_free);
     return true;
   } else {
     return false;
@@ -92,11 +92,11 @@ ISO9660::FS::readdir (const char psz_pat
 /*! Close previously opened ISO 9660 image and free resources
   associated with the image. Call this when done using using an ISO
   9660 image.
-  
+
   @return true is unconditionally returned. If there was an error
   false would be returned.
 */
-bool 
+bool
 ISO9660::IFS::close()
 {
   iso9660_close(p_iso9660);
@@ -107,18 +107,18 @@ ISO9660::IFS::close()
 /*!
   Given a directory pointer, find the filesystem entry that contains
   lsn and return information about it.
-  
+
   Returns Stat*  of entry if we found lsn, or NULL otherwise.
   Caller must release returned object using delete when done.
 */
 ISO9660::Stat *
-ISO9660::IFS::find_lsn(lsn_t i_lsn) 
+ISO9660::IFS::find_lsn(lsn_t i_lsn)
 {
   return new Stat(iso9660_ifs_find_lsn(p_iso9660, i_lsn));
 }
 
-/*!  
-  Return the Joliet level recognized. 
+/*!
+  Return the Joliet level recognized.
 */
 uint8_t
 ISO9660::IFS::get_joliet_level()
@@ -130,7 +130,7 @@ ISO9660::IFS::get_joliet_level()
   Return true if ISO 9660 image has extended attrributes (XA).
 */
 bool
-ISO9660::IFS::is_xa () 
+ISO9660::IFS::is_xa ()
 {
   return iso9660_ifs_is_xa (p_iso9660);
 }
@@ -140,10 +140,10 @@ ISO9660::IFS::is_xa ()
   checks. This may be useful when trying to read an ISO 9660 image
   contained in a file format that libiso9660 doesn't know natively
   (or knows imperfectly.)
-  
+
   Maybe in the future we will have a mode. NULL is returned on
   error.
-  
+
   @see open
 */
 bool
@@ -160,7 +160,7 @@ ISO9660::IFS::open_fuzzy (const char *ps
   PVD object is returned if read, and NULL if there was an error.
 */
 ISO9660::PVD *
-ISO9660::IFS::read_pvd () 
+ISO9660::IFS::read_pvd ()
 {
   iso9660_pvd_t pvd;
   bool b_okay = iso9660_ifs_read_pvd (p_iso9660, &pvd);
@@ -175,7 +175,7 @@ ISO9660::IFS::read_pvd ()
   and datastart and a possible additional offset. Generally here we are
   not reading an ISO 9660 image but a CD-Image which contains an ISO 9660
   filesystem.
-  
+
   @see read_superblock
 */
 bool
@@ -190,110 +190,110 @@ ISO9660::IFS::read_superblock (iso_exten
   and datastart and a possible additional offset. Generally here we are
   not reading an ISO 9660 image but a CD-Image which contains an ISO 9660
   filesystem.
-  
+
   @see read_superblock
 */
-bool 
+bool
 ISO9660::IFS::read_superblock_fuzzy (iso_extension_mask_t iso_extension_mask,
 				     uint16_t i_fuzz)
 {
-  return iso9660_ifs_fuzzy_read_superblock (p_iso9660, iso_extension_mask, 
+  return iso9660_ifs_fuzzy_read_superblock (p_iso9660, iso_extension_mask,
 					    i_fuzz);
 }
 
-char * 
-ISO9660::PVD::get_application_id() 
+char *
+ISO9660::PVD::get_application_id()
 {
   return iso9660_get_application_id(&pvd);
 }
 
-int 
-ISO9660::PVD::get_pvd_block_size() 
+int
+ISO9660::PVD::get_pvd_block_size()
 {
   return iso9660_get_pvd_block_size(&pvd);
 }
 
 /*!
   Return the PVD's preparer ID.
-  NULL is returned if there is some problem in getting this. 
+  NULL is returned if there is some problem in getting this.
 */
-char * 
-ISO9660::PVD::get_preparer_id() 
+char *
+ISO9660::PVD::get_preparer_id()
 {
   return iso9660_get_preparer_id(&pvd);
 }
 
 /*!
   Return the PVD's publisher ID.
-  NULL is returned if there is some problem in getting this. 
+  NULL is returned if there is some problem in getting this.
 */
-char * 
-ISO9660::PVD::get_publisher_id() 
+char *
+ISO9660::PVD::get_publisher_id()
 {
   return iso9660_get_publisher_id(&pvd);
 }
 
 const char *
-ISO9660::PVD::get_pvd_id() 
+ISO9660::PVD::get_pvd_id()
 {
   return iso9660_get_pvd_id(&pvd);
 }
 
-int 
-ISO9660::PVD::get_pvd_space_size() 
+int
+ISO9660::PVD::get_pvd_space_size()
 {
   return iso9660_get_pvd_space_size(&pvd);
 }
 
-uint8_t 
+uint8_t
 ISO9660::PVD::get_pvd_type() {
   return iso9660_get_pvd_type(&pvd);
 }
 
 /*! Return the primary volume id version number (of pvd).
-  If there is an error 0 is returned. 
+  If there is an error 0 is returned.
 */
-int 
-ISO9660::PVD::get_pvd_version() 
+int
+ISO9660::PVD::get_pvd_version()
 {
   return iso9660_get_pvd_version(&pvd);
 }
 
 /*! Return the LSN of the root directory for pvd.
-  If there is an error CDIO_INVALID_LSN is returned. 
+  If there is an error CDIO_INVALID_LSN is returned.
 */
-lsn_t 
-ISO9660::PVD::get_root_lsn() 
+lsn_t
+ISO9660::PVD::get_root_lsn()
 {
   return iso9660_get_root_lsn(&pvd);
 }
 
 /*!
   Return the PVD's system ID.
-  NULL is returned if there is some problem in getting this. 
+  NULL is returned if there is some problem in getting this.
 */
-char * 
-ISO9660::PVD::get_system_id() 
+char *
+ISO9660::PVD::get_system_id()
 {
   return iso9660_get_system_id(&pvd);
 }
 
 /*!
   Return the PVD's volume ID.
-  NULL is returned if there is some problem in getting this. 
+  NULL is returned if there is some problem in getting this.
 */
-char * 
-ISO9660::PVD::get_volume_id() 
+char *
+ISO9660::PVD::get_volume_id()
 {
   return iso9660_get_volume_id(&pvd);
 }
 
 /*!
   Return the PVD's volumeset ID.
-  NULL is returned if there is some problem in getting this. 
+  NULL is returned if there is some problem in getting this.
 */
-char * 
-ISO9660::PVD::get_volumeset_id() 
+char *
+ISO9660::PVD::get_volumeset_id()
 {
   return iso9660_get_volumeset_id(&pvd);
 }
Index: libcdio-0.94/lib/driver/_cdio_stream.c
===================================================================
--- libcdio-0.94.orig/lib/driver/_cdio_stream.c
+++ libcdio-0.94/lib/driver/_cdio_stream.c
@@ -73,7 +73,7 @@ cdio_stream_destroy(CdioDataSource_t *p_
   cdio_stream_close(p_obj);
 
   p_obj->op.free(p_obj->user_data);
-
+  p_obj->user_data = NULL;
   free(p_obj);
 }
 
Index: libcdio-0.94/lib/driver/ds.c
===================================================================
--- libcdio-0.94.orig/lib/driver/ds.c
+++ libcdio-0.94/lib/driver/ds.c
@@ -61,10 +61,10 @@ _cdio_list_new (void)
 }
 
 void
-_cdio_list_free (CdioList_t *p_list, int free_data)
+_cdio_list_free (CdioList_t *p_list, int free_data, CdioDataFree_t free_fn)
 {
   while (_cdio_list_length (p_list))
-    _cdio_list_node_free (_cdio_list_begin (p_list), free_data);
+    _cdio_list_node_free (_cdio_list_begin (p_list), free_data, free_fn);
 
   free (p_list);
 }
@@ -180,7 +180,8 @@ _cdio_list_node_next (CdioListNode_t *p_
 }
 
 void
-_cdio_list_node_free (CdioListNode_t *p_node, int free_data)
+_cdio_list_node_free (CdioListNode_t *p_node,
+                      int free_data, CdioDataFree_t free_fn)
 {
   CdioList_t *p_list;
   CdioListNode_t *prev_node;
@@ -191,8 +192,8 @@ _cdio_list_node_free (CdioListNode_t *p_
 
   cdio_assert (_cdio_list_length (p_list) > 0);
 
-  if (free_data)
-    free (_cdio_list_node_data (p_node));
+  if (free_data && free_fn)
+    free_fn (_cdio_list_node_data (p_node));
 
   if (_cdio_list_length (p_list) == 1)
     {
Index: libcdio-0.94/lib/driver/image/nrg.c
===================================================================
--- libcdio-0.94.orig/lib/driver/image/nrg.c
+++ libcdio-0.94/lib/driver/image/nrg.c
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2003-2006, 2008-2009, 2011-2012, 2014
+  Copyright (C) 2003-2006, 2008-2009, 2011-2012, 2014, 2017
   Rocky Bernstein <rocky@gnu.org>
   Copyright (C) 2001, 2003 Herbert Valerio Riedel <hvr@gnu.org>
 
@@ -1107,7 +1107,7 @@ _free_nrg (void *p_user_data)
 
   if (NULL == p_env) return;
   if (NULL != p_env->mapping)
-    _cdio_list_free (p_env->mapping, true);
+    _cdio_list_free (p_env->mapping, true, free);
 
   /* The remaining part of the image is like the other image drivers,
      so free that in the same way. */
@@ -1275,6 +1275,7 @@ cdio_is_nrg(const char *psz_nrg)
 
   if (!(p_env->gen.data_source = cdio_stdio_new (psz_nrg))) {
     cdio_warn ("can't open nrg image file %s for reading", psz_nrg);
+    free(p_env);
     return false;
   }
 
Index: libcdio-0.94/lib/iso9660/iso9660_fs.c
===================================================================
--- libcdio-0.94.orig/lib/iso9660/iso9660_fs.c
+++ libcdio-0.94/lib/iso9660/iso9660_fs.c
@@ -258,6 +258,7 @@ iso9660_close (iso9660_t *p_iso)
 {
   if (NULL != p_iso) {
     cdio_stdio_destroy(p_iso->stream);
+    p_iso->stream = NULL;
     free(p_iso);
   }
   return true;
@@ -1283,13 +1284,13 @@ iso9660_fs_readdir (CdIo_t *p_cdio, cons
     if (!_dirbuf)
       {
       cdio_warn("Couldn't calloc(1, %d)", p_stat->secsize * ISO_BLOCKSIZE);
-      _cdio_list_free (retval, true);
+      _cdio_list_free (retval, true, NULL);
       return NULL;
       }
 
     if (cdio_read_data_sectors (p_cdio, _dirbuf, p_stat->lsn,
 				ISO_BLOCKSIZE, p_stat->secsize)) {
-      _cdio_list_free (retval, true);
+      _cdio_list_free (retval, true, NULL);
       return NULL;
     }
 
@@ -1351,7 +1352,7 @@ iso9660_ifs_readdir (iso9660_t *p_iso, c
       {
         cdio_warn("Invalid directory buffer sector size %u", p_stat->secsize);
 	iso9660_stat_free(p_stat);
-	_cdio_list_free (retval, true);
+	_cdio_list_free (retval, true, NULL);
         return NULL;
       }
 
@@ -1360,13 +1361,13 @@ iso9660_ifs_readdir (iso9660_t *p_iso, c
       {
         cdio_warn("Couldn't calloc(1, %lu)", dirbuf_len);
 	iso9660_stat_free(p_stat);
-	_cdio_list_free (retval, true);
+	_cdio_list_free (retval, true, NULL);
         return NULL;
       }
 
     ret = iso9660_iso_seek_read (p_iso, _dirbuf, p_stat->lsn, p_stat->secsize);
     if (ret != dirbuf_len) 	  {
-      _cdio_list_free (retval, true);
+      _cdio_list_free (retval, true, NULL);
       iso9660_stat_free(p_stat);
       free (_dirbuf);
       return NULL;
@@ -1400,7 +1401,7 @@ iso9660_ifs_readdir (iso9660_t *p_iso, c
     iso9660_stat_free(p_stat);
 
     if (offset != dirbuf_len) {
-      _cdio_list_free (retval, true);
+      _cdio_list_free (retval, true, (CdioDataFree_t) iso9660_stat_free);
       return NULL;
     }
 
@@ -1437,6 +1438,7 @@ find_lsn_recurse (void *p_image, iso9660
       if (statbuf->type == _STAT_DIR
           && strcmp ((char *) statbuf->filename, ".")
           && strcmp ((char *) statbuf->filename, "..")) {
+	snprintf (*ppsz_full_filename, len, "%s%s/", psz_path, psz_filename);
         _cdio_list_append (dirlist, strdup(*ppsz_full_filename));
       }
 
@@ -1445,19 +1447,19 @@ find_lsn_recurse (void *p_image, iso9660
 	iso9660_stat_t *ret_stat = calloc(1, len2);
 	if (!ret_stat)
 	  {
-	    _cdio_list_free (dirlist, true);
+	    _cdio_list_free (dirlist, true, free);
 	    cdio_warn("Couldn't calloc(1, %d)", len2);
 	    return NULL;
 	  }
 	memcpy(ret_stat, statbuf, len2);
-        _cdio_list_free (entlist, true);
-        _cdio_list_free (dirlist, true);
+        _cdio_list_free (entlist, true, (CdioDataFree_t) iso9660_stat_free);
+        _cdio_list_free (dirlist, true, free);
         return ret_stat;
       }
 
     }
 
-  _cdio_list_free (entlist, true);
+  _cdio_list_free (entlist, true, (CdioDataFree_t) iso9660_stat_free);
 
   /* now recurse/descend over directories encountered */
 
@@ -1472,7 +1474,7 @@ find_lsn_recurse (void *p_image, iso9660
 				   ppsz_full_filename);
 
       if (NULL != ret_stat) {
-        _cdio_list_free (dirlist, true);
+        _cdio_list_free (dirlist, true, free);
         return ret_stat;
       }
     }
@@ -1481,7 +1483,7 @@ find_lsn_recurse (void *p_image, iso9660
     free(*ppsz_full_filename);
     *ppsz_full_filename = NULL;
   }
-  _cdio_list_free (dirlist, true);
+  _cdio_list_free (dirlist, true, free);
   return NULL;
 }
 
@@ -1548,8 +1550,9 @@ void
 iso9660_stat_free(iso9660_stat_t *p_stat)
 {
   if (p_stat != NULL) {
-    if (p_stat->rr.psz_symlink)
+    if (p_stat->rr.psz_symlink) {
       CDIO_FREE_IF_NOT_NULL(p_stat->rr.psz_symlink);
+    }
     free(p_stat);
   }
 }
Index: libcdio-0.94/src/cd-info.c
===================================================================
--- libcdio-0.94.orig/src/cd-info.c
+++ libcdio-0.94/src/cd-info.c
@@ -574,8 +574,8 @@ print_iso9660_recurse (CdIo_t *p_cdio, c
          translated_name = (char *) malloc(translated_name_size);
          if (!translated_name) {
            report( stderr, "Error allocating memory\n" );
-	   _cdio_list_free (p_dirlist, true);
-	   _cdio_list_free (p_entlist, true);
+	   _cdio_list_free (p_dirlist, true, free);
+	   _cdio_list_free (p_entlist, true, (CdioDataFree_t) iso9660_stat_free);
            return;
          }
        }
@@ -605,7 +605,7 @@ print_iso9660_recurse (CdIo_t *p_cdio, c
     }
     free (translated_name);
 
-  _cdio_list_free (p_entlist, true);
+  _cdio_list_free (p_entlist, true, (CdioDataFree_t) iso9660_stat_free);
 
   printf ("\n");
 
@@ -618,7 +618,7 @@ print_iso9660_recurse (CdIo_t *p_cdio, c
       print_iso9660_recurse (p_cdio, _fullname, fs);
     }
 
-  _cdio_list_free (p_dirlist, true);
+  _cdio_list_free (p_dirlist, true, free);
 }
 
 static void
Index: libcdio-0.94/src/iso-info.c
===================================================================
--- libcdio-0.94.orig/src/iso-info.c
+++ libcdio-0.94/src/iso-info.c
@@ -54,6 +54,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
 #if 0
 #define STRONG "\033[1m"
 #define NORMAL "\033[0m"
@@ -228,7 +232,7 @@ print_iso9660_recurse (iso9660_t *p_iso,
   CdioList_t *dirlist =  _cdio_list_new ();
   CdioListNode_t *entnode;
   uint8_t i_joliet_level = iso9660_ifs_get_joliet_level(p_iso);
-  char *translated_name = (char *) malloc(4096);
+  char *translated_name = (char *) alloca(4096);
   size_t translated_name_size = 4096;
   entlist = iso9660_ifs_readdir (p_iso, psz_path);
   if (opts.print_iso9660) {
@@ -236,7 +240,6 @@ print_iso9660_recurse (iso9660_t *p_iso,
   }
 
   if (NULL == entlist) {
-    free(translated_name);
     free(dirlist);
     report( stderr, "Error getting above directory information\n" );
     return;
@@ -244,9 +247,8 @@ print_iso9660_recurse (iso9660_t *p_iso,
 
   rec_counter++;
   if (rec_counter > CDIO_MAX_DIR_RECURSION) {
-    free(translated_name);
     free(dirlist);
-    _cdio_list_free (entlist, true);
+    _cdio_list_free (entlist, true, (CdioDataFree_t) iso9660_stat_free);
     report( stderr,
             "Directory recursion too deep. ISO most probably damaged.\n" );
     return;
@@ -259,14 +261,8 @@ print_iso9660_recurse (iso9660_t *p_iso,
       iso9660_stat_t *p_statbuf = _cdio_list_node_data (entnode);
       char *psz_iso_name = p_statbuf->filename;
       char _fullname[4096] = { 0, };
-       if (strlen(psz_iso_name) >= translated_name_size) {
+      if (strlen(psz_iso_name) >= translated_name_size) {
          translated_name_size = strlen(psz_iso_name)+1;
-         free(translated_name);
-         translated_name = (char *) malloc(translated_name_size);
-         if (!translated_name) {
-           report( stderr, "Error allocating memory\n" );
-           return;
-         }
        }
 
       if (yep != p_statbuf->rr.b3_rock || 1 == opts.no_rock_ridge) {
@@ -291,19 +287,15 @@ print_iso9660_recurse (iso9660_t *p_iso,
                        0 == opts.no_rock_ridge,
                        iso9660_ifs_is_xa(p_iso) && 0 == opts.no_xa,
                        psz_iso_name, translated_name);
-      } else
+      } else {
         if ( strcmp (psz_iso_name, ".") && strcmp (psz_iso_name, ".."))
           printf("%9u %s%s\n", (unsigned int) p_statbuf->size, psz_path,
                  yep == p_statbuf->rr.b3_rock
                  ? psz_iso_name : translated_name);
-      if (p_statbuf->rr.i_symlink) {
-        free(p_statbuf->rr.psz_symlink);
-        p_statbuf->rr.i_symlink = 0;
       }
     }
-    free (translated_name);
 
-  _cdio_list_free (entlist, true);
+  _cdio_list_free (entlist, true, (CdioDataFree_t) iso9660_stat_free);
 
   if (opts.print_iso9660) {
     printf ("\n");
@@ -318,7 +310,7 @@ print_iso9660_recurse (iso9660_t *p_iso,
       print_iso9660_recurse (p_iso, _fullname, rec_counter);
     }
 
-  _cdio_list_free (dirlist, true);
+  _cdio_list_free (dirlist, true, free);
 }
 
 static void
Index: libcdio-0.94/test/testisocd2.c
===================================================================
--- libcdio-0.94.orig/test/testisocd2.c
+++ libcdio-0.94/test/testisocd2.c
@@ -67,6 +67,7 @@ main(int argc, const char *argv[])
 	    ISO9660_IMAGE);
     return 1;
   } else {
+    unsigned int rc=0;
     uint8_t joliet_level = iso9660_ifs_get_joliet_level(p_iso);
     if (joliet_level != 0) {
       printf("Expecting joliet level to be 0, got %u\n", joliet_level);
@@ -74,7 +75,9 @@ main(int argc, const char *argv[])
     } else {
       printf("-- No joliet, as expected.\n");
     }
+    iso9660_close(p_iso);
     p_iso = iso9660_open_ext(ISO9660_IMAGE, ISO_EXTENSION_ALL);
+
     joliet_level = iso9660_ifs_get_joliet_level(p_iso);
     if ( joliet_level != 0) {
       printf("Expecting joliet level to still be 0, got %d\n", joliet_level);
@@ -102,8 +105,8 @@ main(int argc, const char *argv[])
       char buf[ISO_BLOCKSIZE];
       char *psz_path = NULL;
       const lsn_t i_lsn = p_statbuf->lsn;
-      const iso9660_stat_t *p_statbuf2 = iso9660_ifs_find_lsn (p_iso, i_lsn);
-      const iso9660_stat_t *p_statbuf3 =
+      iso9660_stat_t *p_statbuf2 = iso9660_ifs_find_lsn (p_iso, i_lsn);
+      iso9660_stat_t *p_statbuf3 =
 	iso9660_ifs_find_lsn_with_path (p_iso, i_lsn, &psz_path);
 
       /* Compare the two statbufs. */
@@ -113,28 +116,29 @@ main(int argc, const char *argv[])
 
 	  fprintf(stderr, "File stat information between fs_stat and "
 		  "iso9660_ifs_find_lsn isn't the same\n");
-	  iso9660_stat_free(p_statbuf);
-	  exit(3);
+	  rc = 3;
+	  goto exit;
       }
 
       if (p_statbuf3->lsn != p_statbuf2->lsn ||
 	  p_statbuf3->size != p_statbuf2->size ||
 	  p_statbuf3->type != p_statbuf2->type) {
-          iso9660_stat_free(p_statbuf);
-	  exit(4);
+	rc = 4;
+	goto exit;
       }
 
       if (psz_path != NULL) {
 	if (0 != strncmp("/./", psz_path, strlen("/./"))) {
 	  fprintf(stderr, "Path returned for ifs_find_lsn_with_path "
 		  "is not correct should be /./, is %s\n", psz_path);
-          iso9660_stat_free(p_statbuf);
-	  exit(5);
+	  rc = 5;
+	  goto exit;
 	}
 	free(psz_path);
       } else {
 	fprintf(stderr, "Path returned for fs_find_lsn_with_path is NULL\n");
-	iso9660_stat_free(p_statbuf);
+	rc = 6;
+	goto exit;
 	exit(6);
       }
 
@@ -144,11 +148,15 @@ main(int argc, const char *argv[])
 	{
 	  fprintf(stderr, "Error reading ISO 9660 file at lsn %lu\n",
 		  (long unsigned int) p_statbuf->lsn);
-	  iso9660_stat_free(p_statbuf);
-	  exit(7);
+	  rc = 7;
+	  goto exit;
 	}
-      iso9660_stat_free(p_statbuf);
-      exit(0);
+  exit:
+    iso9660_stat_free(p_statbuf2);
+    iso9660_stat_free(p_statbuf3);
+    iso9660_stat_free(p_statbuf);
+    iso9660_close(p_iso);
+    exit(rc);
     }
   }
 
