2006-10-12 17:38:32 +00:00
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
2010-02-14 08:45:14 +00:00
/*
Copyright ( c ) 2006 - 2010 Thomas Schmitt < scdbackup @ gmx . net >
Provided under GPL version 2 or later .
*/
2010-05-16 09:07:42 +00:00
# ifdef HAVE_CONFIG_H
# include "../config.h"
# endif
2006-10-12 17:38:32 +00:00
# include <errno.h>
# include <unistd.h>
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <sys/ioctl.h>
2010-01-15 18:25:14 +00:00
# include <sys/file.h>
2006-10-12 17:38:32 +00:00
# include <stdlib.h>
# include <string.h>
# include <sys/poll.h>
# include <camlib.h>
# include <cam/scsi/scsi_message.h>
# include <cam/scsi/scsi_pass.h>
# include <err.h> /* XXX */
2008-11-15 22:07:24 +00:00
/* ts A70909 */
2007-09-09 13:31:29 +00:00
# include <sys/statvfs.h>
2010-01-21 10:46:04 +00:00
/* ts B00121 */
# include <sys/disk.h> /* DIOCGMEDIASIZE */
2007-09-09 13:31:29 +00:00
2010-03-27 17:27:50 +00:00
/* ts B00326 : For use of CAM_PASS_ERR_RECOVER with ahci */
# define Libburn_for_freebsd_ahcI yes
/* ts B00327 : for debugging of cam_send_cdb() failures
# define Libburn_ahci_verbouS yes
*/
/* ts B00327 : Apply CAM_PASS_ERR_RECOVER to drives even if not ahci
# define libburn_ahci_style_for_alL yes
*/
2006-10-12 17:38:32 +00:00
# include "transport.h"
# include "drive.h"
# include "sg.h"
# include "spc.h"
# include "mmc.h"
# include "sbc.h"
# include "debug.h"
# include "toc.h"
# include "util.h"
2006-10-17 03:09:29 +00:00
# include "libdax_msgs.h"
extern struct libdax_msgs * libdax_messenger ;
2007-01-24 12:44:22 +00:00
struct burn_drive_enumeration_state {
int fd ;
union ccb ccb ;
unsigned int i ;
int skip_device ;
} ;
2006-10-12 17:38:32 +00:00
static void enumerate_common ( char * fname , int bus_no , int host_no ,
int channel_no , int target_no , int lun_no ) ;
/* ts A51221 */
int burn_drive_is_banned ( char * device_address ) ;
/* ts A60821
2007-09-12 10:45:34 +00:00
debug : for tracing calls which might use open drive fds
or for catching SCSI usage of emulated drives . */
int mmc_function_spy ( struct burn_drive * d , char * text ) ;
2006-10-12 17:38:32 +00:00
2006-10-21 18:51:35 +00:00
2010-01-15 18:25:14 +00:00
/* ts B00113
Whether to log SCSI commands :
bit0 = log in / tmp / libburn_sg_command_log
bit1 = log to stderr
bit2 = flush every line
*/
extern int burn_sg_log_scsi ;
/* ts B00114 */
/* Storage object is in libburn/init.c
whether to strive for exclusive access to the drive
*/
extern int burn_sg_open_o_excl ;
2009-12-27 14:45:05 +00:00
/* ts A91227 */
/** Returns the id string of the SCSI transport adapter and eventually
needed operating system facilities .
This call is usable even if sg_initialize ( ) was not called yet . In that
case a preliminary constant message might be issued if detailed info is
not available yet .
@ param msg returns id string
@ param flag unused yet , submit 0
@ return 1 = success , < = 0 = failure
*/
int sg_id_string ( char msg [ 1024 ] , int flag )
{
strcpy ( msg , " internal FreeBSD CAM adapter sg-freebsd " ) ;
return 1 ;
}
/* ts A91227 */
2009-12-25 22:37:57 +00:00
/** Performs global initialization of the SCSI transport adapter and eventually
needed operating system facilities . Checks for compatibility supporting
software components .
@ param msg returns ids and / or error messages of eventual helpers
@ param flag unused yet , submit 0
@ return 1 = success , < = 0 = failure
*/
int sg_initialize ( char msg [ 1024 ] , int flag )
{
2009-12-27 14:45:05 +00:00
return sg_id_string ( msg , 0 ) ;
}
/* ts A91227 */
/** Performs global finalization of the SCSI transport adapter and eventually
needed operating system facilities . Releases globally aquired resources .
@ param flag unused yet , submit 0
@ return 1 = success , < = 0 = failure
*/
int sg_shutdown ( int flag )
{
2009-12-25 22:37:57 +00:00
return 1 ;
}
2009-12-27 14:45:05 +00:00
/** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
struct burn_drive which are defined in os - * . h .
The eventual initialization of those components was made underneath
scsi_enumerate_drives ( ) .
This will be called when a burn_drive gets disposed .
@ param d the drive to be finalized
@ param flag unused yet , submit 0
@ return 1 = success , < = 0 = failure
*/
int sg_dispose_drive ( struct burn_drive * d , int flag )
{
return 1 ;
}
2006-11-15 17:10:12 +00:00
/* ts A61021 : Moved most code from scsi_enumerate_drives under
sg_give_next_adr ( ) */
/* Some helper functions for scsi_give_next_adr() */
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
static int sg_init_enumerator ( burn_drive_enumerator_t * idx_ )
2006-10-21 18:51:35 +00:00
{
2007-01-24 12:44:22 +00:00
struct burn_drive_enumeration_state * idx ;
int bufsize ;
2010-07-12 19:37:31 +00:00
idx = calloc ( 1 , sizeof ( * idx ) ) ;
2007-01-24 12:44:22 +00:00
if ( idx = = NULL ) {
2010-07-12 19:37:31 +00:00
warnx ( " cannot allocate memory for enumerator " ) ;
2007-01-24 12:44:22 +00:00
return - 1 ;
}
2006-10-21 18:51:35 +00:00
idx - > skip_device = 0 ;
if ( ( idx - > fd = open ( XPT_DEVICE , O_RDWR ) ) = = - 1 ) {
2010-07-12 19:37:31 +00:00
warn ( " could not open %s " , XPT_DEVICE ) ;
2009-10-27 10:09:31 +00:00
free ( idx ) ;
idx = NULL ;
2006-10-21 18:51:35 +00:00
return - 1 ;
}
bzero ( & ( idx - > ccb ) , sizeof ( union ccb ) ) ;
idx - > ccb . ccb_h . path_id = CAM_XPT_PATH_ID ;
idx - > ccb . ccb_h . target_id = CAM_TARGET_WILDCARD ;
idx - > ccb . ccb_h . target_lun = CAM_LUN_WILDCARD ;
idx - > ccb . ccb_h . func_code = XPT_DEV_MATCH ;
2007-01-24 12:44:22 +00:00
bufsize = sizeof ( struct dev_match_result ) * 100 ;
idx - > ccb . cdm . match_buf_len = bufsize ;
2010-07-12 19:37:31 +00:00
idx - > ccb . cdm . matches = ( struct dev_match_result * ) calloc ( 1 , bufsize ) ;
2006-10-21 18:51:35 +00:00
if ( idx - > ccb . cdm . matches = = NULL ) {
2010-07-12 19:37:31 +00:00
warnx ( " cannot allocate memory for matches " ) ;
2006-10-21 18:51:35 +00:00
close ( idx - > fd ) ;
2007-01-24 12:44:22 +00:00
free ( idx ) ;
2006-10-21 18:51:35 +00:00
return - 1 ;
}
idx - > ccb . cdm . num_matches = 0 ;
idx - > i = idx - > ccb . cdm . num_matches ; /* to trigger buffer load */
/*
* We fetch all nodes , since we display most of them in the default
* case , and all in the verbose case .
*/
idx - > ccb . cdm . num_patterns = 0 ;
idx - > ccb . cdm . pattern_buf_len = 0 ;
2007-01-24 12:44:22 +00:00
* idx_ = idx ;
2006-10-21 18:51:35 +00:00
return 1 ;
}
2007-01-24 12:44:22 +00:00
static void sg_destroy_enumerator ( burn_drive_enumerator_t * idx_ )
{
struct burn_drive_enumeration_state * idx = * idx_ ;
if ( idx - > fd ! = - 1 )
close ( idx - > fd ) ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
free ( idx - > ccb . cdm . matches ) ;
free ( idx ) ;
* idx_ = NULL ;
}
static int sg_next_enumeration_buffer ( burn_drive_enumerator_t * idx_ )
2006-10-21 18:51:35 +00:00
{
2007-01-24 12:44:22 +00:00
struct burn_drive_enumeration_state * idx = * idx_ ;
2006-10-21 18:51:35 +00:00
/*
* We do the ioctl multiple times if necessary , in case there are
* more than 100 nodes in the EDT .
*/
if ( ioctl ( idx - > fd , CAMIOCOMMAND , & ( idx - > ccb ) ) = = - 1 ) {
warn ( " error sending CAMIOCOMMAND ioctl " ) ;
return - 1 ;
}
if ( ( idx - > ccb . ccb_h . status ! = CAM_REQ_CMP )
| | ( ( idx - > ccb . cdm . status ! = CAM_DEV_MATCH_LAST )
& & ( idx - > ccb . cdm . status ! = CAM_DEV_MATCH_MORE ) ) ) {
warnx ( " got CAM error %#x, CDM error %d \n " ,
idx - > ccb . ccb_h . status , idx - > ccb . cdm . status ) ;
return - 1 ;
}
return 1 ;
}
2010-01-13 07:45:07 +00:00
/** Returns the next index object state and the next enumerated drive address.
2006-10-14 12:24:03 +00:00
@ param idx An opaque handle . Make no own theories about it .
@ param adr Takes the reply
@ param adr_size Gives maximum size of reply including final 0
@ param initialize 1 = start new ,
0 = continue , use no other values for now
- 1 = finish
@ return 1 = reply is a valid address , 0 = no further address available
- 1 = severe error ( e . g . adr_size too small )
*/
2007-01-24 12:44:22 +00:00
int sg_give_next_adr ( burn_drive_enumerator_t * idx_ ,
2006-10-14 12:24:03 +00:00
char adr [ ] , int adr_size , int initialize )
2006-10-12 17:38:32 +00:00
{
2007-01-24 12:44:22 +00:00
struct burn_drive_enumeration_state * idx ;
2006-10-21 18:51:35 +00:00
int ret ;
if ( initialize = = 1 ) {
2007-01-24 12:44:22 +00:00
ret = sg_init_enumerator ( idx_ ) ;
2006-10-21 18:51:35 +00:00
if ( ret < = 0 )
return ret ;
} else if ( initialize = = - 1 ) {
2007-01-24 12:44:22 +00:00
sg_destroy_enumerator ( idx_ ) ;
2006-10-21 18:51:35 +00:00
return 0 ;
}
2006-10-12 17:38:32 +00:00
2007-01-24 12:44:22 +00:00
idx = * idx_ ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
do {
if ( idx - > i > = idx - > ccb . cdm . num_matches ) {
ret = sg_next_enumeration_buffer ( idx_ ) ;
if ( ret < = 0 )
return - 1 ;
idx - > i = 0 ;
} else
( idx - > i ) + + ;
while ( idx - > i < idx - > ccb . cdm . num_matches ) {
switch ( idx - > ccb . cdm . matches [ idx - > i ] . type ) {
case DEV_MATCH_BUS :
break ;
case DEV_MATCH_DEVICE : {
struct device_match_result * result ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
result = & ( idx - > ccb . cdm . matches [ idx - > i ] . result . device_result ) ;
if ( result - > flags & DEV_RESULT_UNCONFIGURED )
idx - > skip_device = 1 ;
else
idx - > skip_device = 0 ;
break ;
}
case DEV_MATCH_PERIPH : {
struct periph_match_result * result ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
result = & ( idx - > ccb . cdm . matches [ idx - > i ] . result . periph_result ) ;
2010-01-13 07:45:07 +00:00
/* ts B00112 : we really want only "cd" devices.
2007-01-24 12:44:22 +00:00
if ( idx - > skip_device | |
strcmp ( result - > periph_name , " pass " ) = = 0 )
break ;
2010-01-13 07:45:07 +00:00
*/
if ( idx - > skip_device | |
strcmp ( result - > periph_name , " cd " ) ! = 0 )
break ;
2007-01-24 12:44:22 +00:00
ret = snprintf ( adr , adr_size , " /dev/%s%d " ,
result - > periph_name , result - > unit_number ) ;
if ( ret > = adr_size )
return - 1 ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
/* Found next enumerable address */
return 1 ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
}
default :
2010-01-13 07:45:07 +00:00
/* fprintf(stderr, "unknown match type\n"); */
2007-01-24 12:44:22 +00:00
break ;
}
( idx - > i ) + + ;
}
} while ( ( idx - > ccb . ccb_h . status = = CAM_REQ_CMP )
& & ( idx - > ccb . cdm . status = = CAM_DEV_MATCH_MORE ) ) ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
return 0 ;
2006-10-12 17:38:32 +00:00
}
2006-10-21 18:51:35 +00:00
2006-10-12 17:38:32 +00:00
int sg_is_enumerable_adr ( char * adr )
{
2006-10-21 18:51:35 +00:00
burn_drive_enumerator_t idx ;
2007-01-24 12:44:22 +00:00
int ret ;
2006-10-21 18:51:35 +00:00
char buf [ 64 ] ;
2007-01-24 12:44:22 +00:00
ret = sg_init_enumerator ( & idx ) ;
if ( ret < = 0 )
return 0 ;
2006-10-21 18:51:35 +00:00
while ( 1 ) {
2007-01-24 12:44:22 +00:00
ret = sg_give_next_adr ( & idx , buf , sizeof ( buf ) , 0 ) ;
2006-10-21 18:51:35 +00:00
if ( ret < = 0 )
2007-01-24 12:44:22 +00:00
break ;
2006-10-21 18:51:35 +00:00
if ( strcmp ( adr , buf ) = = 0 ) {
2007-01-24 12:44:22 +00:00
sg_destroy_enumerator ( & idx ) ;
2006-10-21 18:51:35 +00:00
return 1 ;
}
}
2007-01-24 12:44:22 +00:00
sg_destroy_enumerator ( & idx ) ;
2006-10-12 17:38:32 +00:00
return ( 0 ) ;
}
2006-10-21 18:51:35 +00:00
/** Try to obtain SCSI address parameters.
@ return 1 is success , 0 is failure
*/
2006-10-12 17:38:32 +00:00
int sg_obtain_scsi_adr ( char * path , int * bus_no , int * host_no , int * channel_no ,
int * target_no , int * lun_no )
{
2006-10-21 18:51:35 +00:00
burn_drive_enumerator_t idx ;
2007-01-24 12:44:22 +00:00
int ret ;
2006-10-21 18:51:35 +00:00
char buf [ 64 ] ;
struct periph_match_result * result ;
2007-01-24 12:44:22 +00:00
ret = sg_init_enumerator ( & idx ) ;
if ( ret < = 0 )
return 0 ;
2006-10-21 18:51:35 +00:00
while ( 1 ) {
2007-01-24 12:44:22 +00:00
ret = sg_give_next_adr ( & idx , buf , sizeof ( buf ) , 0 ) ;
2006-10-21 18:51:35 +00:00
if ( ret < = 0 )
2007-01-24 12:44:22 +00:00
break ;
if ( strcmp ( path , buf ) = = 0 ) {
result = & ( idx - > ccb . cdm . matches [ idx - > i ] . result . periph_result ) ;
* bus_no = result - > path_id ;
* host_no = result - > path_id ;
* channel_no = 0 ;
* target_no = result - > target_id ;
* lun_no = result - > target_lun ;
sg_destroy_enumerator ( & idx ) ;
return 1 ;
}
2006-10-21 18:51:35 +00:00
}
2007-01-24 12:44:22 +00:00
sg_destroy_enumerator ( & idx ) ;
2006-10-12 17:38:32 +00:00
return ( 0 ) ;
}
2006-10-21 18:51:35 +00:00
2006-10-12 17:38:32 +00:00
int sg_close_drive ( struct burn_drive * d )
{
if ( d - > cam ! = NULL ) {
cam_close_device ( d - > cam ) ;
d - > cam = NULL ;
}
2010-01-15 18:25:14 +00:00
if ( d - > lock_fd > 0 ) {
close ( d - > lock_fd ) ;
d - > lock_fd = - 1 ;
}
2006-10-12 17:38:32 +00:00
return 0 ;
}
2006-10-21 18:51:35 +00:00
int sg_drive_is_open ( struct burn_drive * d )
{
return ( d - > cam ! = NULL ) ;
}
2006-11-15 17:10:12 +00:00
int scsi_enumerate_drives ( void )
2006-10-12 17:38:32 +00:00
{
2006-10-21 18:51:35 +00:00
burn_drive_enumerator_t idx ;
2007-01-24 12:44:22 +00:00
int ret ;
2006-10-21 18:51:35 +00:00
char buf [ 64 ] ;
2007-01-24 12:44:22 +00:00
struct periph_match_result * result ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
ret = sg_init_enumerator ( & idx ) ;
if ( ret < = 0 )
return 0 ;
2006-10-21 18:51:35 +00:00
while ( 1 ) {
2007-01-24 12:44:22 +00:00
ret = sg_give_next_adr ( & idx , buf , sizeof ( buf ) , 0 ) ;
2006-10-21 18:51:35 +00:00
if ( ret < = 0 )
2007-01-24 12:44:22 +00:00
break ;
2006-10-21 18:51:35 +00:00
if ( burn_drive_is_banned ( buf ) )
2007-01-24 12:44:22 +00:00
continue ;
result = & idx - > ccb . cdm . matches [ idx - > i ] . result . periph_result ;
enumerate_common ( buf , result - > path_id , result - > path_id ,
0 , result - > target_id ,
result - > target_lun ) ;
2006-10-21 18:51:35 +00:00
}
2007-01-24 12:44:22 +00:00
sg_destroy_enumerator ( & idx ) ;
2006-10-21 18:51:35 +00:00
2007-01-24 12:44:22 +00:00
return 1 ;
2006-10-12 17:38:32 +00:00
}
2006-10-21 18:51:35 +00:00
# ifdef Scsi_freebsd_make_own_enumeratE
/* ts A61021: The old version which mixes SCSI and operating system adapter
*/
2006-10-12 17:38:32 +00:00
static void enumerate_common ( char * fname , int bus_no , int host_no ,
int channel_no , int target_no , int lun_no )
{
struct burn_drive * t ;
struct burn_drive out ;
/* ts A60923 */
out . bus_no = bus_no ;
out . host = host_no ;
out . id = target_no ;
out . channel = channel_no ;
out . lun = lun_no ;
out . devname = burn_strdup ( fname ) ;
2010-01-15 18:25:14 +00:00
2006-10-12 17:38:32 +00:00
out . cam = NULL ;
2010-01-15 18:25:14 +00:00
out . lock_fd = - 1 ;
2010-03-27 17:27:50 +00:00
out . is_ahci = 0 ;
2006-10-12 17:38:32 +00:00
2006-10-20 11:34:52 +00:00
out . start_lba = - 2000000000 ;
out . end_lba = - 2000000000 ;
2006-10-21 10:34:15 +00:00
out . read_atip = mmc_read_atip ;
2006-10-20 11:34:52 +00:00
2006-10-12 17:38:32 +00:00
out . grab = sg_grab ;
out . release = sg_release ;
2006-10-21 18:51:35 +00:00
out . drive_is_open = sg_drive_is_open ;
2006-10-12 17:38:32 +00:00
out . issue_command = sg_issue_command ;
out . getcaps = spc_getcaps ;
out . released = 1 ;
out . status = BURN_DISC_UNREADY ;
out . eject = sbc_eject ;
out . load = sbc_load ;
out . lock = spc_prevent ;
out . unlock = spc_allow ;
out . read_disc_info = spc_sense_write_params ;
out . get_erase_progress = spc_get_erase_progress ;
out . test_unit_ready = spc_test_unit_ready ;
out . probe_write_modes = spc_probe_write_modes ;
out . read_toc = mmc_read_toc ;
out . write = mmc_write ;
out . erase = mmc_erase ;
out . read_sectors = mmc_read_sectors ;
out . perform_opc = mmc_perform_opc ;
out . set_speed = mmc_set_speed ;
out . send_parameters = spc_select_error_params ;
out . send_write_parameters = spc_select_write_params ;
out . send_cue_sheet = mmc_send_cue_sheet ;
out . sync_cache = mmc_sync_cache ;
out . get_nwa = mmc_get_nwa ;
out . close_disc = mmc_close_disc ;
out . close_session = mmc_close_session ;
2006-10-30 11:18:36 +00:00
out . close_track_session = mmc_close ;
2006-10-23 12:41:29 +00:00
out . read_buffer_capacity = mmc_read_buffer_capacity ;
2010-07-12 19:37:31 +00:00
out . idata = calloc ( 1 , sizeof ( struct burn_scsi_inquiry_data ) ) ;
2006-10-12 17:38:32 +00:00
out . idata - > valid = 0 ;
2010-07-12 19:37:31 +00:00
out . mdata = calloc ( 1 , sizeof ( struct scsi_mode_data ) ) ;
2006-10-12 17:38:32 +00:00
out . mdata - > valid = 0 ;
2006-10-17 03:09:29 +00:00
if ( out . idata = = NULL | | out . mdata = = NULL ) {
libdax_msgs_submit ( libdax_messenger , - 1 , 0x00020108 ,
LIBDAX_MSGS_SEV_FATAL , LIBDAX_MSGS_PRIO_HIGH ,
" Could not allocate new drive object " , 0 , 0 ) ;
return ;
}
2006-10-12 17:38:32 +00:00
memset ( & out . params , 0 , sizeof ( struct params ) ) ;
t = burn_drive_register ( & out ) ;
/* ts A60821
< < < debug : for tracing calls which might use open drive fds */
2007-09-12 10:45:34 +00:00
mmc_function_spy ( NULL , " enumerate_common : -------- doing grab " ) ;
2006-10-12 17:38:32 +00:00
/* try to get the drive info */
if ( t - > grab ( t ) ) {
burn_print ( 2 , " getting drive info \n " ) ;
t - > getcaps ( t ) ;
t - > unlock ( t ) ;
t - > released = 1 ;
} else {
burn_print ( 2 , " unable to grab new located drive \n " ) ;
}
/* ts A60821
< < < debug : for tracing calls which might use open drive fds */
2007-09-12 10:45:34 +00:00
mmc_function_spy ( NULL , " enumerate_common : ----- would release " ) ;
2006-10-12 17:38:32 +00:00
}
2006-10-21 18:51:35 +00:00
# else /* Scsi_freebsd_make_own_enumeratE */
/* The new, more concise version of enumerate_common */
static void enumerate_common ( char * fname , int bus_no , int host_no ,
int channel_no , int target_no , int lun_no )
{
int ret ;
struct burn_drive out ;
/* General libburn drive setup */
burn_setup_drive ( & out , fname ) ;
/* This transport adapter uses SCSI-family commands and models
( seems the adapter would know better than its boss , if ever ) */
ret = burn_scsi_setup_drive ( & out , bus_no , host_no , channel_no ,
target_no , lun_no , 0 ) ;
if ( ret < = 0 )
return ;
/* Operating system adapter is CAM */
/* Adapter specific handles and data */
out . cam = NULL ;
2010-01-15 18:25:14 +00:00
out . lock_fd = - 1 ;
2010-03-27 17:27:50 +00:00
out . is_ahci = 0 ;
2010-01-15 18:25:14 +00:00
2006-10-21 18:51:35 +00:00
/* Adapter specific functions */
out . grab = sg_grab ;
out . release = sg_release ;
out . drive_is_open = sg_drive_is_open ;
out . issue_command = sg_issue_command ;
/* Finally register drive and inquire drive information */
burn_drive_finish_enum ( & out ) ;
}
# endif /* ! Scsi_freebsd_make_own_enumeratE */
2010-01-15 18:25:14 +00:00
/* Lock the inode associated to dev_fd and the inode associated to devname.
Return OS errno , number of pass device of dev_fd , locked fd to devname ,
error message .
A return value of > 0 means success , < = 0 means failure .
2006-10-12 17:38:32 +00:00
*/
2010-01-15 18:25:14 +00:00
static int freebsd_dev_lock ( int dev_fd , char * devname ,
int * os_errno , int * pass_dev_no , int * lock_fd , char msg [ 4096 ] ,
int flag )
{
int lock_denied = 0 , fd_stbuf_valid , name_stbuf_valid , i , pass_l = 100 ;
int max_retry = 3 , tries = 0 ;
struct stat fd_stbuf , name_stbuf ;
char pass_name [ 16 ] , * lock_name ;
* os_errno = 0 ;
* pass_dev_no = - 1 ;
* lock_fd = - 1 ;
msg [ 0 ] = 0 ;
fd_stbuf_valid = ! fstat ( dev_fd , & fd_stbuf ) ;
/* Try to find name of pass device by inode number */
lock_name = ( char * ) " effective device " ;
if ( fd_stbuf_valid ) {
for ( i = 0 ; i < pass_l ; i + + ) {
sprintf ( pass_name , " /dev/pass%d " , i ) ;
if ( stat ( pass_name , & name_stbuf ) ! = - 1 )
if ( fd_stbuf . st_ino = = name_stbuf . st_ino & &
fd_stbuf . st_dev = = name_stbuf . st_dev )
break ;
}
if ( i < pass_l ) {
lock_name = pass_name ;
* pass_dev_no = i ;
}
}
name_stbuf_valid = ! stat ( devname , & name_stbuf ) ;
for ( tries = 0 ; tries < = max_retry ; tries + + ) {
lock_denied = flock ( dev_fd , LOCK_EX | LOCK_NB ) ;
* os_errno = errno ;
if ( lock_denied ) {
if ( errno = = EAGAIN & & tries < max_retry ) {
/* <<< debugging
fprintf ( stderr ,
" \n libcdio_DEBUG: EAGAIN pass, tries= %d \n " ,
tries ) ;
*/
usleep ( 2000000 ) ;
continue ;
}
sprintf ( msg ,
" Device busy. flock(LOCK_EX) failed on %s of %s " ,
strlen ( lock_name ) > 2000 | | * pass_dev_no < 0 ?
" pass device " : lock_name ,
strlen ( devname ) > 2000 ? " drive " : devname ) ;
return 0 ;
}
break ;
}
/*
fprintf ( stderr , " libburn_DEBUG: flock obtained on %s of %s \n " ,
lock_name , devname ) ;
*/
/* Eventually lock the official device node too */
if ( fd_stbuf_valid & & name_stbuf_valid & &
( fd_stbuf . st_ino ! = name_stbuf . st_ino | |
fd_stbuf . st_dev ! = name_stbuf . st_dev ) ) {
* lock_fd = open ( devname , O_RDONLY ) ;
if ( * lock_fd = = 0 ) {
close ( * lock_fd ) ;
* lock_fd = - 1 ;
} if ( * lock_fd > 0 ) {
for ( tries = 0 ; tries < = max_retry ; tries + + ) {
lock_denied =
flock ( * lock_fd , LOCK_EX | LOCK_NB ) ;
if ( lock_denied ) {
if ( errno = = EAGAIN & &
tries < max_retry ) {
/* <<< debugging
fprintf ( stderr ,
" \n libcdio_DEBUG: EAGAIN dev, tries= %d \n " ,
tries ) ;
*/
usleep ( 2000000 ) ;
continue ;
}
close ( * lock_fd ) ;
* lock_fd = - 1 ;
sprintf ( msg ,
" Device busy. flock(LOCK_EX) failed on %s " ,
strlen ( devname ) > 4000 ? " drive " : devname ) ;
return 0 ;
}
break ;
}
}
/*
fprintf ( stderr , " libburn_DEBUG: flock obtained on %s \n " ,
devname ) ;
*/
}
return 1 ;
}
static int sg_lock ( struct burn_drive * d , int flag )
{
int ret , os_errno , pass_dev_no = - 1 , flock_fd = - 1 ;
char msg [ 4096 ] ;
ret = freebsd_dev_lock ( d - > cam - > fd , d - > devname ,
& os_errno , & pass_dev_no , & flock_fd , msg , 0 ) ;
if ( ret < = 0 ) {
libdax_msgs_submit ( libdax_messenger , d - > global_index ,
0x00020008 ,
LIBDAX_MSGS_SEV_SORRY , LIBDAX_MSGS_PRIO_HIGH ,
msg , os_errno , 0 ) ;
sg_close_drive ( d ) ;
return 0 ;
}
if ( d - > lock_fd > 0 )
close ( d - > lock_fd ) ;
d - > lock_fd = flock_fd ;
return 1 ;
}
2006-10-12 17:38:32 +00:00
int sg_grab ( struct burn_drive * d )
{
struct cam_device * cam ;
2010-03-27 17:27:50 +00:00
char path_string [ 80 ] ;
2006-10-12 17:38:32 +00:00
2007-09-12 10:45:34 +00:00
if ( mmc_function_spy ( d , " sg_grab " ) < = 0 )
return 0 ;
2006-10-17 03:09:29 +00:00
2007-01-24 12:44:22 +00:00
if ( burn_drive_is_open ( d ) ) {
d - > released = 0 ;
return 1 ;
}
2006-10-17 03:09:29 +00:00
2006-10-12 17:38:32 +00:00
cam = cam_open_device ( d - > devname , O_RDWR ) ;
2006-10-17 03:09:29 +00:00
if ( cam = = NULL ) {
2010-01-13 07:45:07 +00:00
libdax_msgs_submit ( libdax_messenger , d - > global_index ,
0x00020003 ,
LIBDAX_MSGS_SEV_SORRY , LIBDAX_MSGS_PRIO_HIGH ,
2010-01-15 18:25:14 +00:00
" Could not grab drive " , errno , 0 ) ;
2006-10-12 17:38:32 +00:00
return 0 ;
2006-10-17 03:09:29 +00:00
}
2010-01-15 18:25:14 +00:00
d - > cam = cam ;
if ( burn_sg_open_o_excl & 63 )
if ( sg_lock ( d , 0 ) < = 0 )
return 0 ;
fcntl ( cam - > fd , F_SETOWN , getpid ( ) ) ;
2010-03-27 17:27:50 +00:00
cam_path_string ( d - > cam , path_string , sizeof ( path_string ) ) ;
# ifdef Libburn_ahci_verbouS
fprintf ( stderr , " libburn_EXPERIMENTAL: CAM path = %s \n " , path_string ) ;
# endif
if ( strstr ( path_string , " :ahcich " ) ! = NULL )
d - > is_ahci = 1 ;
else
d - > is_ahci = - 1 ;
2010-01-15 18:25:14 +00:00
d - > released = 0 ;
return 1 ;
2006-10-12 17:38:32 +00:00
}
2006-10-21 18:51:35 +00:00
2006-10-12 17:38:32 +00:00
/*
non zero return means you still have the drive and it ' s not
in a state to be released ? ( is that even possible ? )
*/
int sg_release ( struct burn_drive * d )
{
2007-09-12 10:45:34 +00:00
if ( mmc_function_spy ( d , " sg_release " ) < = 0 )
return 0 ;
2006-10-17 03:09:29 +00:00
2006-10-12 17:38:32 +00:00
if ( d - > cam = = NULL ) {
burn_print ( 1 , " release an ungrabbed drive. die \n " ) ;
return 0 ;
}
2006-10-17 03:09:29 +00:00
2007-09-12 10:45:34 +00:00
mmc_function_spy ( NULL , " sg_release ----------- closing. " ) ;
2006-10-17 03:09:29 +00:00
2006-10-12 17:38:32 +00:00
sg_close_drive ( d ) ;
2007-01-24 12:44:22 +00:00
d - > released = 1 ;
2006-10-12 17:38:32 +00:00
return 0 ;
}
int sg_issue_command ( struct burn_drive * d , struct command * c )
{
2010-03-29 10:33:05 +00:00
int done = 0 , err , sense_len = 0 , ret , ignore_error , no_retry = 0 ;
2010-07-29 08:35:36 +00:00
int cam_pass_err_recover = 0 , key , asc , ascq ;
2006-10-12 17:38:32 +00:00
union ccb * ccb ;
2006-10-17 03:09:29 +00:00
char buf [ 161 ] ;
2010-01-15 18:25:14 +00:00
static FILE * fp = NULL ;
2006-10-17 03:09:29 +00:00
snprintf ( buf , sizeof ( buf ) , " sg_issue_command d->cam=%p d->released=%d " ,
( void * ) d - > cam , d - > released ) ;
2007-09-12 10:45:34 +00:00
mmc_function_spy ( NULL , buf ) ;
2006-10-17 03:09:29 +00:00
if ( d - > cam = = NULL ) {
c - > error = 0 ;
return 0 ;
}
2010-01-15 18:25:14 +00:00
if ( burn_sg_log_scsi & 1 ) {
if ( fp = = NULL ) {
fp = fopen ( " /tmp/libburn_sg_command_log " , " a " ) ;
fprintf ( fp ,
" \n ----------------------------------------- \n " ) ;
}
}
if ( burn_sg_log_scsi & 3 )
scsi_log_cmd ( c , fp , 0 ) ;
2006-10-17 03:09:29 +00:00
2006-10-12 17:38:32 +00:00
c - > error = 0 ;
ccb = cam_getccb ( d - > cam ) ;
cam_fill_csio ( & ccb - > csio ,
1 , /* retries */
NULL , /* cbfncp */
CAM_DEV_QFRZDIS , /* flags */
MSG_SIMPLE_Q_TAG , /* tag_action */
NULL , /* data_ptr */
0 , /* dxfer_len */
sizeof ( ccb - > csio . sense_data ) , /* sense_len */
0 , /* cdb_len */
30 * 1000 ) ; /* timeout */
switch ( c - > dir ) {
case TO_DRIVE :
ccb - > csio . ccb_h . flags | = CAM_DIR_OUT ;
break ;
case FROM_DRIVE :
ccb - > csio . ccb_h . flags | = CAM_DIR_IN ;
break ;
case NO_TRANSFER :
ccb - > csio . ccb_h . flags | = CAM_DIR_NONE ;
break ;
}
2010-03-26 08:33:22 +00:00
# ifdef Libburn_for_freebsd_ahcI
/* ts B00325 : Advise by Alexander Motin */
/* Runs well on 8-STABLE (23 Mar 2003)
But on 8 - RELEASE cam_send_ccb ( ) returns non - zero with errno 6
on eject . Long lasting TEST UNIT READY cycles break with
errno 16.
*/
2010-03-27 17:27:50 +00:00
# ifdef Libburn_ahci_style_for_alL
{
# else
if ( d - > is_ahci > 0 ) {
# endif
ccb - > ccb_h . flags | = CAM_PASS_ERR_RECOVER ;
cam_pass_err_recover = 1 ;
}
2010-03-26 08:33:22 +00:00
# endif /* Libburn_for_freebsd_ahcI */
2006-10-12 17:38:32 +00:00
ccb - > csio . cdb_len = c - > oplen ;
memcpy ( & ccb - > csio . cdb_io . cdb_bytes , & c - > opcode , c - > oplen ) ;
memset ( & ccb - > csio . sense_data , 0 , sizeof ( ccb - > csio . sense_data ) ) ;
if ( c - > page ) {
ccb - > csio . data_ptr = c - > page - > data ;
if ( c - > dir = = FROM_DRIVE ) {
2009-04-30 07:08:23 +00:00
/* ts A90430 : Ticket 148 , by jwehle :
" On ... FreeBSD 6.4 which has a usb memory reader in
addition to a ATAPI DVD burner sg_issue_command
will hang while the SCSI bus is being scanned "
*/
if ( c - > dxfer_len > = 0 )
ccb - > csio . dxfer_len = c - > dxfer_len ;
else
ccb - > csio . dxfer_len = BUFFER_SIZE ;
2006-10-12 17:38:32 +00:00
/* touch page so we can use valgrind */
memset ( c - > page - > data , 0 , BUFFER_SIZE ) ;
} else {
ccb - > csio . dxfer_len = c - > page - > bytes ;
}
} else {
ccb - > csio . data_ptr = NULL ;
ccb - > csio . dxfer_len = 0 ;
}
do {
2010-03-26 08:33:22 +00:00
memset ( c - > sense , 0 , sizeof ( c - > sense ) ) ;
2006-10-12 17:38:32 +00:00
err = cam_send_ccb ( d - > cam , ccb ) ;
2010-03-27 17:27:50 +00:00
ignore_error = sense_len = 0 ;
/* ts B00325 : CAM_AUTOSNS_VALID advised by Alexander Motin */
if ( ccb - > ccb_h . status & CAM_AUTOSNS_VALID ) {
/* ts B00110 */
/* Better curb sense_len */
sense_len = ccb - > csio . sense_len ;
if ( sense_len > sizeof ( c - > sense ) )
sense_len = sizeof ( c - > sense ) ;
memcpy ( c - > sense , & ccb - > csio . sense_data , sense_len ) ;
2010-07-29 08:35:36 +00:00
spc_decode_sense ( c - > sense , sense_len ,
& key , & asc , & ascq ) ;
if ( sense_len > = 14 & & cam_pass_err_recover & & key )
2010-03-27 17:27:50 +00:00
ignore_error = 1 ;
}
if ( err = = - 1 & & cam_pass_err_recover & & ! ignore_error ) {
# ifdef Libburn_ahci_verbouS
fprintf ( stderr , " libburn_EXPERIMENTAL: errno = %d . cam_errbuf = '%s' \n " , errno , cam_errbuf ) ;
# endif
2010-03-29 10:33:05 +00:00
if ( errno = = ENXIO & & c - > opcode [ 0 ] ! = 0 ) {
2010-03-27 17:27:50 +00:00
/* Operations on empty or ejected tray */
/* MEDIUM NOT PRESENT */
# ifdef Libburn_ahci_verbouS
fprintf ( stderr , " libburn_EXPERIMENTAL: Emulating [2,3A,00] MEDIUM NOT PRESENT \n " ) ;
# endif
2010-07-29 08:35:36 +00:00
c - > sense [ 0 ] = 0x70 ; /*Fixed format sense data*/
2010-03-27 17:27:50 +00:00
c - > sense [ 2 ] = 0x02 ;
c - > sense [ 12 ] = 0x3A ;
c - > sense [ 13 ] = 0x00 ;
sense_len = 14 ;
ignore_error = 1 ;
2010-03-29 10:33:05 +00:00
} else if ( c - > opcode [ 0 ] = = 0 & &
( errno = = EBUSY | | errno = = ENXIO ) ) {
2010-03-27 17:27:50 +00:00
/* Timeout of TEST UNIT READY loop */
2010-03-29 10:33:05 +00:00
/* Inquiries while tray is being loaded */
2010-03-27 17:27:50 +00:00
/*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/
# ifdef Libburn_ahci_verbouS
fprintf ( stderr , " libburn_EXPERIMENTAL: Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE \n " ) ;
# endif
2010-07-29 08:35:36 +00:00
c - > sense [ 0 ] = 0x70 ; /*Fixed format sense data*/
2010-03-27 17:27:50 +00:00
c - > sense [ 2 ] = 0x02 ;
c - > sense [ 12 ] = 0x04 ;
c - > sense [ 13 ] = 0x00 ;
sense_len = 14 ;
ignore_error = 1 ;
} else if ( errno = = EINVAL ) {
/* Inappropriate MODE SENSE */
/* INVALID FIELD IN CDB */
# ifdef Libburn_ahci_verbouS
fprintf ( stderr , " libburn_EXPERIMENTAL: Emulating [5,24,00] INVALID FIELD IN CDB \n " ) ;
# endif
2010-07-29 08:35:36 +00:00
c - > sense [ 0 ] = 0x70 ; /*Fixed format sense data*/
2010-03-27 17:27:50 +00:00
c - > sense [ 2 ] = 0x05 ;
c - > sense [ 12 ] = 0x24 ;
c - > sense [ 13 ] = 0x00 ;
sense_len = 14 ;
ignore_error = 1 ;
}
}
if ( err = = - 1 & & ! ignore_error ) {
2006-10-17 03:09:29 +00:00
libdax_msgs_submit ( libdax_messenger ,
d - > global_index , 0x0002010c ,
LIBDAX_MSGS_SEV_FATAL , LIBDAX_MSGS_PRIO_HIGH ,
" Failed to transfer command to drive " ,
errno , 0 ) ;
sg_close_drive ( d ) ;
d - > released = 1 ;
d - > busy = BURN_DRIVE_IDLE ;
c - > error = 1 ;
2010-01-15 18:25:14 +00:00
{ ret = - 1 ; goto ex ; }
2006-10-17 03:09:29 +00:00
}
2006-10-12 17:38:32 +00:00
/* XXX */
2010-01-13 07:45:07 +00:00
2006-10-12 17:38:32 +00:00
if ( ( ccb - > ccb_h . status & CAM_STATUS_MASK ) ! = CAM_REQ_CMP ) {
2010-03-26 08:33:22 +00:00
if ( sense_len < 14 ) {
/*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/
2010-03-27 17:27:50 +00:00
# ifdef Libburn_ahci_verbouS
fprintf ( stderr , " libburn_EXPERIMENTAL: CAM_STATUS= %d .Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE \n " , ( ccb - > ccb_h . status & CAM_STATUS_MASK ) ) ;
# endif
2010-07-29 08:35:36 +00:00
c - > sense [ 0 ] = 0x70 ; /*Fixed format sense data*/
2010-03-26 08:33:22 +00:00
c - > sense [ 2 ] = 0x02 ;
c - > sense [ 12 ] = 0x04 ;
c - > sense [ 13 ] = 0x00 ;
2010-03-29 10:33:05 +00:00
no_retry = 1 ;
2010-03-26 08:33:22 +00:00
}
2010-03-29 10:33:05 +00:00
if ( no_retry | | ignore_error | | ! c - > retry ) {
2006-10-12 17:38:32 +00:00
c - > error = 1 ;
2010-01-15 18:25:14 +00:00
{ ret = 1 ; goto ex ; }
2006-10-12 17:38:32 +00:00
}
switch ( scsi_error ( d , c - > sense , 0 ) ) {
case RETRY :
done = 0 ;
2010-03-29 10:33:05 +00:00
if ( burn_sg_log_scsi & 3 ) {
/* >>> Need own duration time
measurement . Then remove bit1 */
scsi_log_err ( c , fp , c - > sense , 0 ,
( c - > error ! = 0 ) | 2 ) ;
scsi_log_cmd ( c , fp , 0 ) ;
}
2006-10-12 17:38:32 +00:00
break ;
case FAIL :
done = 1 ;
c - > error = 1 ;
break ;
}
} else {
done = 1 ;
}
} while ( ! done ) ;
2010-01-15 18:25:14 +00:00
ret = 1 ;
ex : ;
if ( c - > error )
scsi_notify_error ( d , c , c - > sense , 18 , 0 ) ;
if ( burn_sg_log_scsi & 3 )
/* >>> Need own duration time measurement. Then remove bit1 */
scsi_log_err ( c , fp , c - > sense , 0 , ( c - > error ! = 0 ) | 2 ) ;
2006-10-12 17:38:32 +00:00
cam_freeccb ( ccb ) ;
2010-01-15 18:25:14 +00:00
return ret ;
2006-10-12 17:38:32 +00:00
}
2007-09-09 13:31:29 +00:00
2010-01-16 12:51:24 +00:00
/* ts B00115 */
/* Return 1 if the given path leads to a regular file or a device that can be
seeked , read and eventually written with 2 kB granularity .
*/
int burn_os_is_2k_seekrw ( char * path , int flag )
{
struct stat stbuf ;
char * spt ;
int i , e ;
if ( stat ( path , & stbuf ) = = - 1 )
return 0 ;
if ( S_ISREG ( stbuf . st_mode ) )
return 1 ;
if ( ! S_ISCHR ( stbuf . st_mode ) )
return 0 ;
spt = strrchr ( path , ' / ' ) ;
if ( spt = = NULL )
spt = path ;
else
spt + + ;
e = strlen ( spt ) ;
for ( i = strlen ( spt ) - 1 ; i > 0 ; i - - )
if ( spt [ i ] > = ' 0 ' & & spt [ i ] < = ' 9 ' )
e = i ;
if ( strncmp ( spt , " da " , e ) = = 0 ) /* SCSI disk. E.g. USB stick. */
return 1 ;
if ( strncmp ( spt , " cd " , e ) = = 0 ) /* SCSI CD drive might be writeable. */
return 1 ;
if ( strncmp ( spt , " ad " , e ) = = 0 ) /* IDE hard drive */
return 1 ;
if ( strncmp ( spt , " acd " , e ) = = 0 ) /* IDE CD drive might be writeable */
return 1 ;
if ( strncmp ( spt , " fd " , e ) = = 0 ) /* Floppy disk */
return 1 ;
if ( strncmp ( spt , " fla " , e ) = = 0 ) /* Flash drive */
return 1 ;
return 0 ;
}
2007-09-09 13:31:29 +00:00
/* ts A70909 */
/** Estimate the potential payload capacity of a file address.
@ param path The address of the file to be examined . If it does not
exist yet , then the directory will be inquired .
@ param bytes This value gets modified if an estimation is possible
@ return - 2 = cannot perform necessary operations on file object
- 1 = neither path nor dirname of path exist
0 = could not estimate size capacity of file object
1 = estimation has been made , bytes was set
*/
int burn_os_stdio_capacity ( char * path , off_t * bytes )
{
struct stat stbuf ;
struct statvfs vfsbuf ;
char testpath [ 4096 ] , * cpt ;
long blocks ;
off_t add_size = 0 ;
2010-01-21 10:46:04 +00:00
int fd , ret ;
2007-09-09 13:31:29 +00:00
testpath [ 0 ] = 0 ;
blocks = * bytes / 512 ;
if ( stat ( path , & stbuf ) = = - 1 ) {
strcpy ( testpath , path ) ;
cpt = strrchr ( testpath , ' / ' ) ;
if ( cpt = = NULL )
strcpy ( testpath , " . " ) ;
else if ( cpt = = testpath )
testpath [ 1 ] = 0 ;
else
* cpt = 0 ;
if ( stat ( testpath , & stbuf ) = = - 1 )
return - 1 ;
# ifdef Libburn_if_this_was_linuX
} else if ( S_ISBLK ( stbuf . st_mode ) ) {
2008-11-15 22:07:24 +00:00
int open_mode = O_RDWR , fd , ret ;
2007-09-09 13:31:29 +00:00
if ( burn_sg_open_o_excl )
open_mode | = O_EXCL ;
fd = open ( path , open_mode ) ;
if ( fd = = - 1 )
return - 2 ;
ret = ioctl ( fd , BLKGETSIZE , & blocks ) ;
close ( fd ) ;
if ( ret = = - 1 )
return - 2 ;
* bytes = ( ( off_t ) blocks ) * ( off_t ) 512 ;
# endif /* Libburn_if_this_was_linuX */
2010-01-21 10:46:04 +00:00
} else if ( S_ISCHR ( stbuf . st_mode ) ) {
fd = open ( path , O_RDONLY ) ;
if ( fd = = - 1 )
return - 2 ;
ret = ioctl ( fd , DIOCGMEDIASIZE , & add_size ) ;
close ( fd ) ;
if ( ret = = - 1 )
return - 2 ;
* bytes = add_size ;
2007-09-09 13:31:29 +00:00
} else if ( S_ISREG ( stbuf . st_mode ) ) {
add_size = stbuf . st_blocks * ( off_t ) 512 ;
strcpy ( testpath , path ) ;
} else
return 0 ;
if ( testpath [ 0 ] ) {
if ( statvfs ( testpath , & vfsbuf ) = = - 1 )
return - 2 ;
2010-01-13 07:45:07 +00:00
* bytes = add_size + ( ( off_t ) vfsbuf . f_frsize ) *
2007-09-09 13:31:29 +00:00
( off_t ) vfsbuf . f_bavail ;
}
return 1 ;
}
2009-11-23 18:56:18 +00:00
/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
# ifdef Libburn_read_o_direcT
/* No special O_DIRECT-like precautions are implemented here */
# endif /* Libburn_read_o_direcT */
int burn_os_open_track_src ( char * path , int open_flags , int flag )
{
int fd ;
fd = open ( path , open_flags ) ;
return fd ;
}
void * burn_os_alloc_buffer ( size_t amount , int flag )
{
void * buf = NULL ;
buf = calloc ( 1 , amount ) ;
return buf ;
}
int burn_os_free_buffer ( void * buffer , size_t amount , int flag )
{
2009-11-25 12:21:12 +00:00
if ( buffer = = NULL )
return 0 ;
2009-11-23 18:56:18 +00:00
free ( buffer ) ;
return 1 ;
}