1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
/*
* frag.c
*
* This file is part of libhimd, a library for accessing Sony HiMD devices.
*
* Copyright (C) 2009-2011 Michael Karcher
* Copyright (C) 2011 MÃ¥rten Cassel
* Copyright (C) 2011 Thomas Arp
*
* This library 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.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "himd.h"
#include <string.h>
#define MIN_HOLE 4
#define NO_SUCH_HOLE 0xffff
static int search_hole(struct himd_holelist * holes, int block)
{
int startidx = 0;
int endidx = holes->holecnt-1;
while(startidx != endidx)
{
int mididx = (startidx + endidx)/2;
if(holes->holes[mididx].lastblock < block)
startidx = mididx+1;
else
endidx = mididx;
}
/* block is not in a hole */
if(holes->holes[startidx].firstblock > block)
return NO_SUCH_HOLE;
return startidx;
}
/**
* Find all holes in current HiMD data and return them in himd_holelist.
* This call is required prior to any write operation to HiMD data to
* be able to collect necessary space to store the fragments of a track to be
* written.
*
* @param himd Pointer to a descriptor of previously opened HiMD data
* @param holes Pointer to a list of holes, is filled out by himd_find_holes
* @param status Pointer to himderrinfo, returns error code after operation
*
* @return Returns 0 if successful, -1 otherwise
*/
int himd_find_holes(struct himd * himd, struct himd_holelist * holes, struct himderrinfo * status)
{
int i;
holes->holecnt = 1;
holes->holes[0].firstblock = 0;
holes->holes[0].lastblock = 0xFFFF;
for(i = HIMD_FIRST_FRAGMENT;i < HIMD_LAST_FRAGMENT;i++)
{
struct fraginfo frag;
int splitidx;
if(himd_get_fragment_info(himd, i, &frag, status) < 0)
return -1;
if(frag.firstblock == 0 && frag.lastblock == 0)
continue; /* unused fragment */
splitidx = search_hole(holes, frag.firstblock);
/* If splitidx == NO_SUCH_HOLE, the fragment probably is so small that
the hole had been erased due to minhole */
if(splitidx == NO_SUCH_HOLE)
continue;
/* a fragment splits a hole into two holes (the one before and
the one after the fragment). Either of these two holes might
be too small to be considered, in which case these holes are
discarded, or, spoken another way, the used areas are collapsed
into one used area. */
if(frag.firstblock - holes->holes[splitidx].firstblock < MIN_HOLE)
{
/* collapse at the beginning */
holes->holes[splitidx].firstblock = frag.lastblock + 1;
if(holes->holes[splitidx].lastblock < holes->holes[splitidx].firstblock ||
holes->holes[splitidx].lastblock - holes->holes[splitidx].firstblock < MIN_HOLE)
{
/* this hole has been "completely" filled by the fragment */
memmove(holes->holes + splitidx, holes->holes + splitidx + 1,
(holes->holecnt - splitidx - 1) * sizeof(holes->holes[0]));
holes->holecnt--;
}
}
else
{
/* doesn't collapse at the beginning */
if(holes->holes[splitidx+1].firstblock - frag.lastblock < MIN_HOLE)
/* but collapses at the end */
holes->holes[splitidx].lastblock = frag.firstblock - 1;
else
{
memmove(holes->holes + splitidx + 1, holes->holes + splitidx,
(holes->holecnt - splitidx) * sizeof(holes->holes[0]));
holes->holecnt++;
holes->holes[splitidx].lastblock = frag.firstblock - 1;
holes->holes[splitidx+1].firstblock = frag.lastblock + 1;
}
}
}
return 0;
}
|