Hi, xmms2-devel!

Some days ago I've wandered on cppcheck[1] utility, decided to
give it a try on some projects I use to use and it eventually found
some real resource leaks!

Fixing them is usually not so hard so it can be a good start in a new
project.

I hope I've properly fixed obvious ones (avahi ones need review from
more experienced people)

There is yet some frightening cppcheck reports[3], which I failed to fix.
That code seems to call for serious restructuring.

Whole set of patches is available at git repo:
    git://repo.or.cz/xmms2-devel/slyfox.git cppcheck_resleaks

See patches in text/plain attach. I've already got some feedback
on them, so I don't expect to merge them as-is [2]

The question is whether you need these patches and if so: in what
way I should restructure/send them?

Thanks!

[1]
http://apps.sourceforge.net/trac/cppcheck/
Run as
    $ cppcheck .
or
    $ cppcheck --all --force .
for paranoid mode.

[2] on #xmms2
00:24:58 < _caotic_> That bool variable that get's malloced and freed in the 
daap plugin is already broken. That it might not get freed correctly is a minor 
problem in that code.
00:25:57 < trofi> yes, cppcheck complains a lot in daap code
00:26:10 < trofi> i gave up trying to do something with it
00:26:56 < Gibheer> CFLAGS does not change anything
00:27:24 < trofi> it seems to pass that gmalloc'ed bool to avahi priv state
00:27:32 < trofi> so, might be not so broken
00:30:15 < _caotic_> trofi: I think it would be better to use two different 
callback functions instead of passing true or 
                     false to one common callback functions

[3]
[./src/plugins/daap/daap_xform.c:221]: (error) Memory leak: login_data
[./src/plugins/daap/daap_xform.c:298]: (error) Memory leak: data
[./src/plugins/daap/daap_xform.c:315]: (error) Memory leak: login_data

-- 

  Sergei
commit 04d6e480cb35cdfd0de3d791d5e321ada37b0c77
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Tue Jan 12 00:04:04 2010 +0200

    OTHED: sid: cppcheck: [./src/plugins/sid/sidplay_wrapper.cpp:184]: 
(possible error) Memory leak: rs
    
    Fixed ReSIDBuilder object leak in error paths.
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/plugins/sid/sidplay_wrapper.cpp 
b/src/plugins/sid/sidplay_wrapper.cpp
index 2f1c74a..87d6649 100644
--- a/src/plugins/sid/sidplay_wrapper.cpp
+++ b/src/plugins/sid/sidplay_wrapper.cpp
@@ -139,75 +139,79 @@ sidplay_wrapper_set_subtune (struct sidplay_wrapper 
*wrap, gint subtune)
        wrap->player->load (wrap->currTune);
 }
 
 
 gint
 sidplay_wrapper_load (struct sidplay_wrapper *wrap, const void *buf, gint len)
 {
        int res;
 
        wrap->currTune = new SidTuneMD5 (0);
        res = wrap->currTune->read ((const uint_least8_t *)buf, len);
        if (!res) {
                return -2;
        }
 
        wrap->currTune->selectSong (1);
 
        res = wrap->player->load (wrap->currTune);
        if (res) {
                return -3;
        }
 
        wrap->currTune->GetMD5 (wrap->md5);
 
        ReSIDBuilder *rs = new ReSIDBuilder ("ReSID");
        if (!rs) {
                return -4;
        }
 
        if (!*rs) {
+               delete rs;
                return -5;
        }
 
        rs->create ((wrap->player->info ()).maxsids);
        if (!*rs) {
+               delete rs;
                return -6;
        }
 
        rs->filter (false);
        if (!*rs) {
+               delete rs;
                return -6;
        }
 
        rs->sampling (44100);
        if (!*rs) {
+               delete rs;
                return -6;
        }
 
        wrap->conf              = wrap->player->config ();
        wrap->conf.frequency    = 44100;
        wrap->conf.precision    = 16;
        wrap->conf.playback     = sid2_stereo;
        wrap->conf.sampleFormat = SID2_LITTLE_SIGNED;
 
        /* These should be configurable ... */
        wrap->conf.clockSpeed    = SID2_CLOCK_CORRECT;
        wrap->conf.clockForced   = true;
        wrap->conf.sidModel      = SID2_MODEL_CORRECT;
        wrap->conf.optimisation  = SID2_DEFAULT_OPTIMISATION;
        wrap->conf.sidSamples    = true;
        wrap->conf.clockDefault  = SID2_CLOCK_PAL;
        wrap->conf.sidDefault    = SID2_MOS6581;
 
        wrap->conf.sidEmulation = rs;
        res = wrap->player->config (wrap->conf);
 
        return res;
 }
 
 const char *
 sidplay_wrapper_error (struct sidplay_wrapper *wrap)
 {
        return wrap->player->error ();
 }
 

commit 614466be74d0d1f9f983495239e9b3e3dd0e5d78
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Tue Jan 12 00:00:31 2010 +0200

    OTHER: daap_mdns_avahi: cppcheck resource leak fixes:
    
    [./src/plugins/daap/daap_mdns_avahi.c:123]: (possible error) Memory leak: 
server
    [./src/plugins/daap/daap_mdns_avahi.c:142]: (error) Memory leak: b
    
    Moved memory allocation/deallocation away from leaky paths.
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/plugins/daap/daap_mdns_avahi.c 
b/src/plugins/daap/daap_mdns_avahi.c
index 7549434..9d2c77f 100644
--- a/src/plugins/daap/daap_mdns_avahi.c
+++ b/src/plugins/daap/daap_mdns_avahi.c
@@ -64,111 +64,113 @@ daap_mdns_serv_remove (GSList *serv_list, gchar *addr, 
guint port)
                }
        }
        return NULL;
 }
 
 static void
 daap_mdns_resolve_cb (AvahiServiceResolver *resolv,
                       AvahiIfIndex iface,
                       AvahiProtocol proto,
                       AvahiResolverEvent event,
                       const gchar *name,
                       const gchar *type,
                       const gchar *domain,
                       const gchar *hostname,
                       const AvahiAddress *addr,
                       guint16 port,
                       AvahiStringList *text,
                       AvahiLookupResultFlags flags,
                       void *userdata)
 {
        gboolean *remove = userdata;
        gchar ad[ADDR_LEN];
        daap_mdns_server_t *server;
 
        if (!resolv) {
                return;
        }
 
        switch (event) {
                case AVAHI_RESOLVER_FOUND:
-                       server = g_new0 (daap_mdns_server_t, 1);
                        avahi_address_snprint (ad, sizeof (ad), addr);
 
-                       server->server_name = g_strdup (name);
-                       server->address = g_strdup (ad);
-                       server->mdns_hostname = g_strdup (hostname);
-                       server->port = port;
-
                        if (*remove) {
                                g_static_mutex_lock (&serv_list_mut);
                                g_server_list = daap_mdns_serv_remove 
(g_server_list, ad, port);
                                g_static_mutex_unlock (&serv_list_mut);
                        } else {
+                               server = g_new0 (daap_mdns_server_t, 1);
+                               server->server_name = g_strdup (name);
+                               server->address = g_strdup (ad);
+                               server->mdns_hostname = g_strdup (hostname);
+                               server->port = port;
+
                                g_static_mutex_lock (&serv_list_mut);
                                g_server_list = g_slist_prepend (g_server_list, 
server);
                                g_static_mutex_unlock (&serv_list_mut);
                        }
                        g_free (remove);
 
                        break;
 
                case AVAHI_RESOLVER_FAILURE:
                        break;
 
                default:
                        break;
        }
 
        avahi_service_resolver_free (resolv);
 }
 
 static void
 daap_mdns_browse_cb (AvahiServiceBrowser *browser,
                      AvahiIfIndex iface,
                      AvahiProtocol proto,
                      AvahiBrowserEvent event,
                      const gchar *name,
                      const gchar *type,
                      const gchar *domain,
                      AvahiLookupResultFlags flags,
                      void *userdata)
 {
        gboolean ok = FALSE;
-       gboolean *b = g_malloc (sizeof (gboolean));
+       gboolean *b;
 
        AvahiClient *client = ((browse_callback_userdata_t *) userdata)->client;
 
        if (!browser) {
                return;
        }
 
+       b = g_malloc (sizeof (gboolean));
+
        switch (event) {
                case AVAHI_BROWSER_NEW:
                        *b = FALSE;
                        ok = (gboolean)
                             avahi_service_resolver_new (client, iface, proto, 
name, type,
                                                         domain, 
AVAHI_PROTO_UNSPEC, 0,
                                                         daap_mdns_resolve_cb, 
b);
                        break;
 
                case AVAHI_BROWSER_REMOVE:
                        *b = TRUE;
                        ok = (gboolean)
                             avahi_service_resolver_new (client, iface, proto, 
name, type,
                                                         domain, 
AVAHI_PROTO_UNSPEC, 0,
                                                         daap_mdns_resolve_cb, 
b);
                        break;
 
                case AVAHI_BROWSER_CACHE_EXHAUSTED:
                        break;
 
                case AVAHI_BROWSER_ALL_FOR_NOW:
                        break;
 
                default:
                        break;
        }
 }
 
 static void
 daap_mdns_client_cb (AvahiClient *client,

commit e828977493286f4741252b8ecfa077e6738a6580
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Mon Jan 11 23:52:54 2010 +0200

    OTHER: ices: cppcheck: [./src/plugins/ices/encode.c:130]: (error) Memory 
leak: s
    
    Fixed memleak on error case (nom_br <= 0).
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/plugins/ices/encode.c b/src/plugins/ices/encode.c
index f8d9085..7fe50e1 100644
--- a/src/plugins/ices/encode.c
+++ b/src/plugins/ices/encode.c
@@ -96,66 +96,68 @@ xmms_ices_encoder_create (encoder_state *s, vorbis_comment 
*vc)
        ogg_stream_packetin (&s->os, &header[2]);
 
        s->in_header = TRUE;
        s->flushing = FALSE;
        s->samples_in_current_page = 0;
        s->previous_granulepos = 0;
        s->encoder_inited = TRUE;
 
        return TRUE;
 }
 
 /* Free the ogg and vorbis encoder state associated with
  * encoder_state, if the encoder is present.
  */
 static void
 xmms_ices_encoder_free (encoder_state *s)
 {
        if (s->encoder_inited) {
                ogg_stream_clear (&s->os);
                vorbis_block_clear (&s->vb);
                vorbis_dsp_clear (&s->vd);
                vorbis_info_clear (&s->vi);
                s->encoder_inited = FALSE;
        }
 }
 
 
 encoder_state *
 xmms_ices_encoder_init (int min_br, int nom_br, int max_br)
 {
-       encoder_state *s = g_new0 (encoder_state, 1);
+       encoder_state *s;
 
        /* If none of these are set, it's obviously not supposed to be managed 
*/
        if (nom_br <= 0)
                return NULL;
 
+       s = g_new0 (encoder_state, 1);
+
        s->min_br = min_br;
        s->nom_br = nom_br;
        s->max_br = max_br;
        s->serial = 0;
        s->in_header = FALSE;
        s->encoder_inited = FALSE;
 
        return s;
 }
 
 void xmms_ices_encoder_fini (encoder_state *s) {
        xmms_ices_encoder_free (s);
        g_free (s);
 }
 
 /* Start a new logical ogg stream. */
 gboolean xmms_ices_encoder_stream_change (encoder_state *s, int rate,
                                           int channels, vorbis_comment *vc)
 {
        xmms_ices_encoder_free (s);
        s->rate = rate;
        s->channels = channels;
        return xmms_ices_encoder_create (s, vc);
 }
 
 /* Encode the given data into Ogg Vorbis. */
 void xmms_ices_encoder_input (encoder_state *s, xmms_samplefloat_t *buf, int 
bytes)
 {
        float **buffer;
        int i,j;

commit c8185a480be1aa83fe73156674bbf09e3c29bd34
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Mon Jan 11 23:37:35 2010 +0200

    OTHER: mdns-avahi: [./src/clients/mdns/avahi/mdns-avahi.c:117]: (error) 
Deallocating a deallocated pointer: name
    
    Here we try to fix a bunch of errors:
    * we are trying to g_free statically allocated data on uname(2) failure
    * we are assuming g_main_loop_quit is a noreturn function and thus
      g_free'ing 'name' more, than once
    * we don't free avahi group on error
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/clients/mdns/avahi/mdns-avahi.c 
b/src/clients/mdns/avahi/mdns-avahi.c
index 45059ed..9dd5ce8 100644
--- a/src/clients/mdns/avahi/mdns-avahi.c
+++ b/src/clients/mdns/avahi/mdns-avahi.c
@@ -68,87 +68,93 @@ group_callback (AvahiEntryGroup *g,
 
        switch (state) {
                case AVAHI_ENTRY_GROUP_ESTABLISHED:
                        printf ("_xmms2._tcp port: %d is registered\n", port);
                        break;
                case AVAHI_ENTRY_GROUP_COLLISION:
                        printf ("Got group collsion... terminating...\n");
                        g_main_loop_quit (ml);
                        break;
                case AVAHI_ENTRY_GROUP_FAILURE:
                        g_main_loop_quit (ml);
                        break;
                case AVAHI_ENTRY_GROUP_UNCOMMITED:
                case AVAHI_ENTRY_GROUP_REGISTERING:
                        ;
        }
 
 }
 
 static void
 create_services (AvahiClient *c)
 {
        int ret;
        struct utsname uts;
        gchar *name;
 
        g_return_if_fail (c);
 
        if (uname (&uts) != 0) {
                printf ("failed to run uname()\n");
-               name = "xmms2";
+               name = g_strdup ("xmms2");
        } else {
                name = g_strdup (uts.nodename);
        }
 
        if (!group) {
                if (!(group = avahi_entry_group_new (c, group_callback, NULL))) 
{
                        printf ("couldn't create new group!\n");
+                       g_free (name);
                        g_main_loop_quit (ml);
+                       return;
                }
        }
 
        if ((ret = avahi_entry_group_add_service (group, AVAHI_IF_UNSPEC,
                                                  AVAHI_PROTO_UNSPEC,
                                                  0, name, "_xmms2._tcp",
                                                  NULL, NULL, port, NULL)) < 0)
        {
                printf ("couldn't add entry to group: %s\n", avahi_strerror 
(ret));
                g_free (name);
                g_main_loop_quit (ml);
+               avahi_entry_group_free (group);
+               return;
        }
 
        g_free (name);
 
        if ((ret = avahi_entry_group_commit (group)) < 0) {
                printf ("couldn't commit group: %s\n", avahi_strerror (ret));
                g_main_loop_quit (ml);
+               avahi_entry_group_free (group);
+               return;
        }
 
        return;
 }
 
 static void
 client_callback (AvahiClient *c,
                  AvahiClientState state,
                  void *userdata)
 {
        g_return_if_fail (c);
 
        switch (state) {
                case AVAHI_CLIENT_S_RUNNING:
                        if (!group) {
                                create_services (c);
                        }
                        break;
                case AVAHI_CLIENT_S_COLLISION:
                        printf ("Client collision, terminating...");
                        g_main_loop_quit (ml);
                        break;
                case AVAHI_CLIENT_FAILURE:
                        printf ("Client failure: %s\n", avahi_strerror 
(avahi_client_errno (c)));
                        g_main_loop_quit (ml);
                        break;
                case AVAHI_CLIENT_CONNECTING:
                case AVAHI_CLIENT_S_REGISTERING:
                        ;
        }

commit 5df600f7991538b17c9845ca158153616b29ec5d
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Mon Jan 11 23:21:27 2010 +0200

    OTHER: cppcheck: [./src/clients/nycli/commands.c:925]: (error) Memory leak: 
p
    
    Handled one more deallocation properly in error case.
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/clients/nycli/commands.c b/src/clients/nycli/commands.c
index 14faeec..4d1e564 100644
--- a/src/clients/nycli/commands.c
+++ b/src/clients/nycli/commands.c
@@ -895,60 +895,61 @@ cmd_flag_pos_get (cli_infos_t *infos, command_context_t 
*ctx, gint *pos)
                /* No flag given, just enqueue */
                *pos = infos->cache->active_playlist->len;
        }
 
        return TRUE;
 }
 
 /* Check if url is a dir, used if matching_browse arg isn't a pattern
    (should have a better way) */
 static gint
 url_isdir (cli_infos_t *infos, const gchar *const url)
 {
        xmmsc_result_t *res;
        xmmsv_t *val, *entry;
        gchar *p, *path, *urls = NULL, *fullurl, *scheme;
        const gchar *cpath;
        gint ret = 0;
 
        p = g_strdup (url);
 
        if ((urls = strstr (p, "://"))) {
                urls += 3;
        } else {
                /* Expects a scheme */
                g_free (p);
                return 0;
        }
 
        ret = strlen (urls);
        if (ret && urls[ret - 1] == '/') {
+               g_free (p);
                return 1;
        }
        ret = 0;
 
        for (path = urls + strlen (urls) - 1; path != urls && *path == '/'; 
--path) {
                *path = '\0';
        }
        scheme = g_strndup (p, urls - p);
 
        /* g_path_get_dirname has no notion of URLs, so
         * split the scheme part and work with the filename
         * part, remove the basename then concatenate the
         * scheme and path part back together
         */
        path = g_path_get_dirname (urls);
        fullurl = g_strconcat (scheme, urls, NULL);
        urls = g_strconcat (scheme, path, NULL);
        g_free (path);
        g_free (scheme);
        g_free (p);
 
        res = xmmsc_xform_media_browse_encoded (infos->sync, urls);
        xmmsc_result_wait (res);
        val = xmmsc_result_get_value (res);
 
        if (!xmmsv_is_error (val)) {
                xmmsv_list_iter_t *it;
                xmmsv_get_list_iter (val, &it);
                for (xmmsv_list_iter_first (it);
                     xmmsv_list_iter_valid (it);

commit ceeb252e49cb6d7dc0c28234af4d67b39d5321c5
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Mon Jan 11 23:14:06 2010 +0200

    [./src/xmms/streamtype.c:118]: (error) Memory leak: val
    
    val is allocated in xmms_stream_type_parse and is not
    freed in error case.
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/xmms/streamtype.c b/src/xmms/streamtype.c
index c499e11..b91caf2 100644
--- a/src/xmms/streamtype.c
+++ b/src/xmms/streamtype.c
@@ -88,60 +88,61 @@ xmms_stream_type_parse (va_list ap)
                if (key == XMMS_STREAM_TYPE_END)
                        break;
 
                if (key == XMMS_STREAM_TYPE_NAME) {
                        res->name = g_strdup (va_arg (ap, char *));
                        continue;
                }
 
                if (key == XMMS_STREAM_TYPE_PRIORITY) {
                        res->priority = va_arg (ap, int);
                        continue;
                }
 
                val = g_new0 (xmms_stream_type_val_t, 1);
                val->key = key;
 
                switch (val->key) {
                case XMMS_STREAM_TYPE_MIMETYPE:
                case XMMS_STREAM_TYPE_URL:
                        val->type = STRING;
                        val->d.string = g_strdup (va_arg (ap, char *));
                        break;
                case XMMS_STREAM_TYPE_FMT_FORMAT:
                case XMMS_STREAM_TYPE_FMT_CHANNELS:
                case XMMS_STREAM_TYPE_FMT_SAMPLERATE:
                        val->type = INT;
                        val->d.num = va_arg (ap, int);
                        break;
                default:
                        XMMS_DBG ("UNKNOWN TYPE!!");
+                       g_free (val);
                        return NULL;
                }
                res->list = g_list_append (res->list, val);
        }
 
        if (!res->name) {
                const gchar *mime = xmms_stream_type_get_str (res, 
XMMS_STREAM_TYPE_MIMETYPE);
                const gchar *url = xmms_stream_type_get_str (res, 
XMMS_STREAM_TYPE_URL);
 
                if (mime && url) {
                        res->name = g_strconcat (mime, ":", url, NULL);
                } else if (mime) {
                        res->name = g_strdup (mime);
                } else {
                        g_assert_not_reached ();
                }
 
                g_strdelimit (res->name, ".", '_');
        }
 
        if (res->priority < 0) {
                res->priority = XMMS_STREAM_TYPE_PRIORITY_DEFAULT;
        }
 
        return res;
 }
 
 const char *
 xmms_stream_type_get_str (const xmms_stream_type_t *st, xmms_stream_type_key_t 
key)
 {

commit ba08c969376824b0b565cc341f2b201a3a889bef
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Mon Jan 11 22:59:46 2010 +0200

    [./src/xmms/bindata.c:260]: (error) Resource leak: fp
    
    bindata file was not closed in some subtle error cases.
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/xmms/bindata.c b/src/xmms/bindata.c
index 30cafec..90f5877 100644
--- a/src/xmms/bindata.c
+++ b/src/xmms/bindata.c
@@ -230,60 +230,61 @@ static xmmsv_t *
 xmms_bindata_client_retrieve (xmms_bindata_t *bindata, const gchar *hash,
                               xmms_error_t *err)
 {
        xmmsv_t *res;
        gchar *path;
        GString *str;
        FILE *fp;
 
        path = xmms_bindata_build_path (bindata, hash);
 
        fp = fopen (path, "rb");
        if (!fp) {
                xmms_log_error ("Requesting '%s' which is not on the server", 
hash);
                xmms_error_set (err, XMMS_ERROR_NOENT, "File not found!");
                g_free (path);
                return NULL;
        }
 
        g_free (path);
 
        str = g_string_new (NULL);
        while (!feof (fp)) {
                gchar buf[1024];
                gint l;
 
                l = fread (buf, 1, 1024, fp);
                if (ferror (fp)) {
                        g_string_free (str, TRUE);
                        xmms_log_error ("Error reading bindata '%s'", hash);
                        xmms_error_set (err, XMMS_ERROR_GENERIC, "Error reading 
file");
+                       fclose (fp);
                        return NULL;
                }
                g_string_append_len (str, buf, l);
        }
 
        fclose (fp);
 
        res = xmmsv_new_bin ((unsigned char *)str->str, str->len);
 
        g_string_free (str, TRUE);
 
        return res;
 }
 
 static void
 xmms_bindata_client_remove (xmms_bindata_t *bindata, const gchar *hash,
                             xmms_error_t *err)
 {
        gchar *path;
        path = xmms_bindata_build_path (bindata, hash);
        if (unlink (path) == -1) {
                xmms_error_set (err, XMMS_ERROR_GENERIC, "Couldn't remove 
file");
        }
        g_free (path);
        return;
 }
 
 static GList *
 xmms_bindata_client_list (xmms_bindata_t *bindata, xmms_error_t *err)
 {

commit 9ca3e9a75797ca6e71051a6d66ced5d9f5f44f71
Author: Sergei Trofimovich <sly...@inbox.ru>
Date:   Mon Jan 11 22:56:37 2010 +0200

    OTHER: cppcheck: [./src/clients/cli/main.c:204]: (possible error) Resource 
leak: fp
    
    Config file was not freed after reading and parsing it.
    Thanks to cppcheck.
    
    Signed-off-by: Sergei Trofimovich <sly...@inbox.ru>

diff --git a/src/clients/cli/main.c b/src/clients/cli/main.c
index fc09a5a..477b113 100644
--- a/src/clients/cli/main.c
+++ b/src/clients/cli/main.c
@@ -165,60 +165,61 @@ read_config (void)
                        fclose (fp);
                } else {
                        print_info ("Could not create configfile: %s\nMake sure 
you have write permissions to that location.", file);
                }
        }
 
        if (g_file_test (file, G_FILE_TEST_EXISTS)) {
                fp = fopen (file, "r");
                if (!fp) {
                        print_error ("Could not open configfile %s", file);
                }
                g_free (file);
 
                if (fstat (fileno (fp), &st) == -1) {
                        print_error ("fstat");
                }
 
                buffer = g_malloc0 (st.st_size + 1);
 
                while (read_bytes < st.st_size) {
                        guint ret = fread (buffer + read_bytes,
                                           st.st_size - read_bytes, 1, fp);
 
                        if (ret == 0) {
                                break;
                        }
 
                        read_bytes += ret;
                        g_assert (read_bytes >= 0);
                }
+               fclose (fp);
 
                config = parse_config (buffer);
 
                g_free (buffer);
        } else {
                g_free (file);
                config = parse_config (defaultconfig);
        }
 
        return config;
 }
 
 
 static void
 free_config (void)
 {
        if (config) {
                g_hash_table_destroy (config);
        }
 }
 
 
 /**
  * Usage
  */
 static void
 cmd_help (xmmsc_connection_t *conn, gint argc, gchar **argv)
 {
 
        gint i;

Attachment: signature.asc
Description: PGP signature

--
_______________________________________________
Xmms2-devel mailing list
Xmms2-devel@lists.xmms.se
http://lists.xmms.se/cgi-bin/mailman/listinfo/xmms2-devel

Reply via email to