blob: ab6b5269b2bbd7a1271d5b6136998c34060590a1 [file] [log] [blame]
/* im_close.c --- close an image
*
* Copyright: Nicos Dessipris
* Written on: 12/04/1990
* Modified on :
* 24/7/92 JC
* - im_update_descfile code tidied up
* - free on NULL string when junking Hist fixed
* - now calls im_unmapfile
* - better behaviour if image has been opened and closed with
* no im_setupout call
* - better behaviour for half-made IMAGE descriptors
* 15/4/93 JC
* - additions for freeing partial images
* 29/4/93 JC
* - close callback list added
* 10/5/93 JC
* - im__close() added
* 9/11/93 JC
* - im_update_descfile -> write_descfile
* - if Hist is NULL, no longer makes up and writes .desc file
* 16/8/94 JC
* - evalend callbacks added
* - ANSIfied
* 24/10/95 JC
* - now tracks open images ... see also im_init() and debug.c
* 11/7/00 JC
* - SETBUF_FOREIGN added
* 16/1/04 JC
* - frees as much as possible on im_close() failure
* 6/6/05 Markus Wollgarten
* - free Meta on close
* 30/6/05 JC
* - actually, free Meta on final close, so we carry meta over on an
* im__close()/im_openin() pair (eg. see im_pincheck())
* 11/7/05
* - call im__writehist() to send history to XML after image data
* 3/1/07
* - free history_list
* 7/11/07
* - added preclose, removed evalend triggers
* 23/7/08
* - im__close() will no longer free regions
* 9/8/08
* - lock global image list (thanks Lee)
* 8/9/09
* - move close callbacks *after* we have released resources --- we
* can now write close callbacks that unlink() temporary files
* - use preclose callbacks if you want to run before resources are
* released
* 6/10/09
* - gtkdoc comment
* 10/1/09
* - added postclose
* 14/1/09
* - added written
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define DEBUG_IO
#define DEBUG_NEW
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#ifdef HAVE_IO_H
#include <io.h>
#endif /*HAVE_IO_H*/
#include <assert.h>
#include <vips/vips.h>
#include <vips/thread.h>
#include <vips/internal.h>
#include <vips/debug.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* Maximum file name length.
*/
#define NAMELEN 1024
/* Free any resources owned by this descriptor. The descriptor is left as if a
* call to im_init had just happened - ie. the filename is set, but no other
* resources are attached. Information is lost if this is a im_setbuf()
* image! On an error, return non-zero and leave the image in an indeterminate
* state. Too hard to recover gracefully.
*/
int
im__close( IMAGE *im )
{
int result;
result = 0;
/* No action for NULL image.
*/
if( !im )
return( result );
#ifdef DEBUG_IO
printf( "im__close: starting for %s ..\n", im->filename );
#endif /*DEBUG_IO*/
/* Trigger all pre-close fns.
*/
result |= im__trigger_callbacks( im->preclosefns );
IM_FREEF( im_slist_free_all, im->preclosefns );
/* Should be no regions defined on the image. im_close() ought to put
* us into a zombie state if there are, im__close() should not be
* called on images with running regions.
*/
if( im->regions ) {
GSList *p;
printf( "** im__close: leaked regions!\n" );
for( p = im->regions; p; p = p->next )
im_region_print( (REGION *) p->data );
}
/* That should mean we have no windows.
*/
if( im->windows ) {
GSList *p;
printf( "** im__close: leaked windows!\n" );
for( p = im->windows; p; p = p->next )
im_window_print( (im_window_t *) p->data );
}
/* Junk generate functions.
*/
im->start = NULL;
im->generate = NULL;
im->stop = NULL;
/* No more upstream/downstream links.
*/
im__link_break_all( im );
/* What resources are associated with this IMAGE descriptor?
*/
if( im->baseaddr ) {
/* MMAP file.
*/
#ifdef DEBUG_IO
printf( "im__close: unmapping file ..\n" );
#endif /*DEBUG_IO*/
if( im_unmapfile( im ) )
return( -1 );
im->data = NULL;
}
/* Is there a file descriptor?
*/
if( im->fd != -1 ) {
#ifdef DEBUG_IO
printf( "im__close: closing output file ..\n" );
#endif /*DEBUG_IO*/
if( im->dtype == IM_OPENOUT && im__writehist( im ) )
result = -1;
if( close( im->fd ) == -1 ) {
im_error( "im_close", _( "unable to close fd for %s" ),
im->filename );
result = -1;
}
im->fd = -1;
}
/* Any image data?
*/
if( im->data ) {
/* Buffer image. Only free stuff we know we allocated.
*/
if( im->dtype == IM_SETBUF ) {
#ifdef DEBUG_IO
printf( "im__close: freeing buffer ..\n" );
#endif /*DEBUG_IO*/
im_free( im->data );
im->dtype = IM_NONE;
}
im->data = NULL;
}
/* Junk all callbacks, perform close callbacks.
*/
IM_FREEF( im_slist_free_all, im->evalstartfns );
IM_FREEF( im_slist_free_all, im->evalfns );
IM_FREEF( im_slist_free_all, im->evalendfns );
IM_FREEF( im_slist_free_all, im->invalidatefns );
IM_FREEF( im_slist_free_all, im->writtenfns );
result |= im__trigger_callbacks( im->closefns );
IM_FREEF( im_slist_free_all, im->closefns );
/* Reset other state.
*/
im->dtype = IM_NONE;
im->dhint = IM_SMALLTILE;
im->kill = 0;
im->close_pending = 0;
im->sizeof_header = IM_SIZEOF_HEADER;
#ifdef DEBUG_IO
printf( "im__close: final success for %s (%p)\n",
im->filename, im );
#endif /*DEBUG_IO*/
return( result );
}
/**
* im_close:
* @im: image to close
*
* Frees all resources associated with @im.
*
* If there are open #REGION s on @im, close is delayed until the last region
* is freed.
*
* See also: im_open().
*
* Returns: 0 on success and 1 on error.
*/
int
im_close( IMAGE *im )
{
int result = 0;
/* No action for NULL image.
*/
if( !im )
return( result );
if( im->regions ) {
/* There are regions left on this image.
* Set close_pending and return. The image will be then
* be closed when the last region is freed
* (see im_region_free()).
*/
#ifdef DEBUG_NEW
printf( "im_close: pending close for 0x%p, \"%s\"\n",
im, im->filename );
#endif /*DEBUG_NEW*/
im->close_pending = 1;
}
else if( !im->closing ) {
/* Is this descriptor currently being closed somewhere else?
* This prevents infinite descent if a close callback
* includes an im_close for this image.
*/
im->closing = 1;
if( im__close( im ) )
result = -1;
#ifdef DEBUG_NEW
printf( "im_close: freeing IMAGE 0x%p, \"%s\"\n",
im, im->filename );
#endif /*DEBUG_NEW*/
/* Final cleanup.
*/
result |= im__trigger_callbacks( im->postclosefns );
IM_FREEF( im_slist_free_all, im->postclosefns );
IM_FREEF( g_mutex_free, im->sslock );
IM_FREE( im->filename );
IM_FREE( im->Hist );
IM_FREEF( im__gslist_gvalue_free, im->history_list );
im__meta_destroy( im );
g_mutex_lock( im__global_lock );
im__open_images = g_slist_remove( im__open_images, im );
g_mutex_unlock( im__global_lock );
im__time_destroy( im );
IM_FREE( im );
}
return( result );
}