source: svn/newcon3bcm2_21bu/nexus/modules/file/src/nexus_file_fifo_chunk.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 58.7 KB
Line 
1/***************************************************************************
2 *     (c)2005-2011 Broadcom Corporation
3 *
4 *  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5 *  and may only be used, duplicated, modified or distributed pursuant to the terms and
6 *  conditions of a separate, written license agreement executed between you and Broadcom
7 *  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8 *  no license (express or implied), right to use, or waiver of any kind with respect to the
9 *  Software, and Broadcom expressly reserves all rights in and to the Software and all
10 *  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11 *  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12 *  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
13 *
14 *  Except as expressly set forth in the Authorized License,
15 *
16 *  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17 *  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18 *  and to use this information only in connection with your use of Broadcom integrated circuit products.
19 *
20 *  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21 *  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22 *  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23 *  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25 *  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26 *  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27 *  USE OR PERFORMANCE OF THE SOFTWARE.
28 *
29 *  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30 *  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31 *  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32 *  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33 *  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34 *  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35 *  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36 *  ANY LIMITED REMEDY.
37 *
38 * $brcm_Workfile: nexus_file_fifo_chunk.c $
39 * $brcm_Revision: 7 $
40 * $brcm_Date: 10/12/11 7:56a $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/file/src/nexus_file_fifo_chunk.c $
47 *
48 * 7   10/12/11 7:56a dlwin
49 * SW7231-352: Added code to silence Coverity 32988 issue.
50 *
51 * 6   8/31/11 2:07p vsilyaev
52 * SW7231-351: Fixed typo
53 *
54 * 5   8/29/11 2:47p vsilyaev
55 * SW7231-351: Fixed typo
56 *
57 * 4   8/15/11 3:47p mphillip
58 * SW7335-1249: Added option to periodically write metadata into a disk
59 *  file
60 *
61 * 3   2/25/11 12:47p erickson
62 * SW7125-818: use BNAV_GetEntrySize
63 *
64 * 2   5/11/10 11:17a jtna
65 * SW7405-4313: Coverity Defect ID:21991 FORWARD_NULL
66 *
67 * 1   4/22/10 6:57p mphillip
68 * SW7405-4251: Merge chunked PVR support from branch to main
69 *
70 * SW7405-3587/4   4/22/10 12:01p mphillip
71 * SW7405-4251: Update chunked PVR after API review, prepare for merge to
72 *  main.
73 *
74 * SW7405-3587/3   4/15/10 11:31a mphillip
75 * SW7405-3587: Update with header changes
76 *
77 * SW7405-3587/2   2/22/10 5:23p mphillip
78 * SW7405-3587: Properly reference sub-chunk files
79 *
80 * SW7405-3587/1   2/4/10 10:21a mphillip
81 * SW7405-3587: Chunked fifo
82 *
83 ***************************************************************************/
84#include "nexus_file_module.h"
85#include "bstd.h"
86#include "bkni.h"
87#include "bkni_multi.h"
88#include "blst_queue.h"
89#include "bcmplayer.h"
90#include "bcmindexer.h"
91#include "bfile_io.h"
92#include "nexus_file_pvr.h"
93#include "nexus_file_types.h"
94#include "nexus_file_posix.h"
95
96#include "unistd.h"
97
98BDBG_MODULE(fileio_fifo_chunk);
99
100
101
102struct bpvrfifo_entry {
103    off_t size; /* size of the entry */
104    off_t voff; /* file 'virtual' offset */
105    off_t doff; /* disk 'physical' offset */
106    unsigned no; /* chunk no */
107};
108
109struct bpvrfifo_signature {
110    char signature[16];
111};
112
113static const struct bpvrfifo_signature bpvrfifo_signature =
114{
115    "bpvrFiFo 0.3"
116};
117static void bfile_fifo_write_snapshot_locked(struct NEXUS_ChunkedFifoRecord *file);
118
119#define TEMPLATE_SIZE 128
120#define FILE_NAME_SIZE 2048
121
122#define BFIFO_N_ENTRYS  512
123#define BFIFO_INVALID_CHUNK ((unsigned)(-1))
124struct bpvrfifo_header {
125    /* we use dual lock scheme, lock is acquired every time when header table is accessed,  and busy flag is set wherever there is an active transaction, in this manner we allow simultaneous read and write transactions, and effectively serialize trim with both read and write */
126    BKNI_MutexHandle lock;
127    unsigned busy; /* busy counter, if busy > 0 then there is an active write or read, and trim has to fail */
128    unsigned prev_trim;     /* previously trimmed value */
129    unsigned trim_gap;      /* Gap between real start of file and next trim point */
130    bool chunked;
131    bool active;
132    unsigned trim_count;
133    union {
134        struct {
135            struct bpvrfifo_signature signature;
136            struct bpvrfifo_entry entrys[BFIFO_N_ENTRYS+1];
137            enum {
138                bpvrfifo_type_master=0, /* master (record file) */
139                bpvrfifo_type_snapshot=1, /* read only snapshot file) */
140                bpvrfifo_type_zombie=2, /* deleted master file, with active snapshots */
141                bpvrfifo_type_unit=3 /* single, not chunked, file */
142            } type; /* type of file */
143            union {
144                struct {
145                    unsigned chunk_no[BFIFO_N_ENTRYS];
146                    uint16_t chunk_ref_cnt[BFIFO_N_ENTRYS];
147                    char chunkTemplate[TEMPLATE_SIZE]; /* template for the chunk name */
148                } master;
149                struct {
150                    char chunkTemplate[TEMPLATE_SIZE]; /* template for the chunk name */
151                    char master_file[FILE_NAME_SIZE]; /* name of the master file (only used for delete operations) */
152                } snapshot;
153            } meta;
154        } h;
155        uint8_t buf[24*1024]; /* for performance reasons header shall be multiplier of the FS block size */
156    } data; /* this is persistent portion of index (e.g. part that is saved on the disk */
157};
158#define B_ENTRY(f,i) (&(f)->header->data.h.entrys[(i)])
159#define b_lock(x) BKNI_AcquireMutex(x->header->lock)
160#define b_unlock(x) BKNI_ReleaseMutex(x->header->lock)
161
162struct bfile_io_write_fifo {
163    struct bfile_io_write self;
164    const struct bpvrfifo_entry *entry_cache; /* cached value of file entry */
165    struct bfile_io_write_posix data;
166    struct bfile_io_write_posix chunk_data; /* data chunk */
167    unsigned chunk_data_no;
168    struct bpvrfifo_header *header;
169    struct bpvrfifo_header _header;
170    off_t offset; /* current virtual offset, also known as a file size */
171    off_t size; /* size of the file on a disk */
172    off_t start;  /* offset, where writeable area begins */
173    unsigned ref_cnt; /* number of references, including itself */
174    unsigned next_chunk;
175    char chunk_name[FILE_NAME_SIZE];
176    struct bfile_io_write_posix data_; /* placeholder */
177    struct bfile_io_write_posix chunk_data_;
178    bool direct;
179    char file_name[FILE_NAME_SIZE];
180    struct bfile_io_write_fifo *meta; /* file to save meta data */
181    off_t meta_offset;
182    off_t meta_size;
183    struct NEXUS_ChunkedFifoRecord *writeSnapshotFile;
184};
185
186struct bfile_io_read_fifo {
187    struct bfile_io_read self;
188    struct bfile_io_read_posix data;
189    struct bfile_io_read_posix chunk_data; /* data chunk */
190    unsigned chunk_data_no;
191    struct bpvrfifo_entry *entry_cache; /* cached value of file entry */
192    unsigned trim_count;
193    struct bpvrfifo_header *header;
194    off_t cur_pos; /* current virtual offset */
195    struct bfile_io_write_fifo *writer;
196    char chunk_name[FILE_NAME_SIZE];
197    struct bfile_io_read_posix data_; /* placeholder */
198    struct bfile_io_read_posix chunk_data_; /* placeholder */
199    bool direct;
200    char file_name[FILE_NAME_SIZE];
201    const char *chunkTemplate;
202    char master_name[FILE_NAME_SIZE];
203    struct bfile_io_read_fifo *meta; /* file to save meta data */
204    off_t meta_offset;
205};
206
207#define B_ENTRY_CLEAR(entry) do{ (entry)->no=BFIFO_INVALID_CHUNK;(entry)->doff=-1;(entry)->voff=0;(entry)->size=0;}while(0)
208#define B_ENTRY_IS_EMPTY(entry) ((entry)->no==BFIFO_INVALID_CHUNK)
209
210#if 0
211#define BDBG_MSG_IO(i, x) BDBG_INSTANCE_MSG(i, x)
212#else
213#define BDBG_MSG_IO(i, x)
214#endif
215
216#if 0
217#define B_DUMP_ENTRY(file, i) BDBG_MSG_IO(file, ("%#x:%u %lld %lld %u", file, i, B_ENTRY(file,i)->voff, B_ENTRY(file,i)->doff, (unsigned)B_ENTRY(file,i)->size))
218#else
219#define B_DUMP_ENTRY(file, i)
220#endif
221
222#if 0
223#define B_DUMP_ENTRYS(file) do{unsigned i;for(i=0;i<BFIFO_N_ENTRYS;i++) {B_DUMP_ENTRY(file,i);if(B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) {break;}}}while(0)
224#else
225#define B_DUMP_ENTRYS(file)
226#endif
227
228#ifdef DIRECT_IO_SUPPORT
229/* we need to maintain data file aligned by 4096 (for DIRECT I/O) and 188 aligned to keep it valid transport packet */
230/* it rounds in 192K */
231#define B_DATA_ALIGN  ((188/4)*4096)
232#else
233#define B_DATA_ALIGN  (188)
234#endif
235
236static const char b_file_chunkTemplate[]="%s_%d%03d";
237
238void NEXUS_ChunkedFifoRecord_GetDefaultSettings(
239    NEXUS_ChunkedFifoRecordSettings *pSettings /* [out] */
240    )
241{
242    BKNI_Memset(pSettings, 0, sizeof(NEXUS_ChunkedFifoRecordSettings));
243    pSettings->interval = 30;
244    pSettings->data.soft = 512*1024*1024;
245    pSettings->data.hard = 1024*1024*1024;
246    pSettings->data.soft -= pSettings->data.soft % B_DATA_ALIGN;
247    pSettings->data.hard -= pSettings->data.hard % B_DATA_ALIGN;
248    pSettings->index.soft = 4*1024*1024;
249    pSettings->index.hard = 8*1024*1024;
250    BKNI_Snprintf(pSettings->chunkTemplate,TEMPLATE_SIZE,"%s",b_file_chunkTemplate);
251}
252
253static ssize_t
254b_read(struct bfile_io_read_posix *fd, void *buf, size_t count)
255{
256    return fd->self.read(&fd->self, buf, count);
257}
258
259static off_t
260b_rseek(struct bfile_io_read_posix *fd, off_t offset, int whence)
261{
262    return fd->self.seek(&fd->self, offset, whence);
263}
264
265static ssize_t
266b_write(struct bfile_io_write_posix *fd, const void *buf, size_t count)
267{
268    return fd->self.write(&fd->self, buf, count);
269}
270
271static off_t
272b_wseek(struct bfile_io_write_posix *fd, off_t offset, int whence)
273{
274    return bfile_io_write_posix_seek(fd, offset, whence);
275}
276
277static NEXUS_Error
278b_pvrfifo_write_sync(struct bfile_io_write_fifo *file)
279{
280    void *buf;
281    off_t off, rc_off;
282    int rc;
283    NEXUS_Error b_rc = NEXUS_SUCCESS;
284
285    off = file->meta_offset;
286
287    if(file->meta != file) { /* lock meta file if we aren't meta */
288        for(;;) {
289            b_lock(file->meta);
290            if(file->meta->header->busy==0) {
291                break;
292            }
293            b_unlock(file->meta);
294            BDBG_WRN(("b_pvrfifo_write_sync: %#lx collision in access to the meta file %#lx", (unsigned long)file, (unsigned long)file->meta));
295            BKNI_Sleep(1);
296        }
297    }
298    if(file->meta_size < off+sizeof(file->header->data)) {
299        file->meta_size = off+sizeof(file->header->data);
300    }
301
302    rc_off = b_wseek(&file->meta->data, off, SEEK_SET);
303    if(rc_off != off) {
304        b_rc = BERR_TRACE(NEXUS_UNKNOWN);
305        goto done;
306    }
307    buf = &file->header->data;
308    rc = b_write(&file->meta->data, buf, sizeof(file->header->data));
309    if(rc!=sizeof(file->header->data)) {
310        b_rc = BERR_TRACE(NEXUS_UNKNOWN);
311        goto done;
312    }
313
314done:
315    if(file->meta != file) {
316        b_unlock(file->meta);
317    }
318    return b_rc;
319}
320
321static void
322b_pvrfifo_write_next_unit(struct bfile_io_write_fifo *file)
323{
324    struct bpvrfifo_entry *entry;
325    unsigned i;
326
327    entry = B_ENTRY(file, 0);
328    /* reached the end of file, now is a time to allocate new chunk */
329    if (entry->doff == file->start) {
330        BDBG_MSG_IO(file, ("write tail"));
331        /* try to allocate new entry at the end of file */
332        for(entry=NULL,i=1;i<BFIFO_N_ENTRYS;i++) {
333            entry = B_ENTRY(file, i);
334            if(entry->doff==-1) { /* empty entry */
335                if(entry[-1].doff + entry[-1].size < file->size) { /* last entry shall not span to the end of file */
336                    entry->voff = file->offset;
337                    entry->doff = entry[-1].doff + entry[-1].size;
338                    entry->size = 0;
339                    entry->no = file->next_chunk;
340                } else {
341                    BDBG_MSG(("bpvrfifo_write: %#lx no space at the end of file", (unsigned long)file));
342                    entry = NULL;
343               }
344               break;
345            }
346        }
347        if(!entry) {
348            BDBG_MSG(("bpvrfifo_write: %#lx overflow", (unsigned long)file));
349        }
350    } else {
351        BDBG_MSG_IO(file, ("write wraparound"));
352        for(i=0;i<BFIFO_N_ENTRYS;i++) {  /* find first not empty entry */
353            if(B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) {
354                break;
355            }
356        }
357        /* new entry _always_ should go on top, so shift old entrys down, so we could keep entries sorted by the 'doff' field */
358        for(;i>0;i--) {
359            *B_ENTRY(file,i) = *B_ENTRY(file, i-1);
360        }
361        entry = B_ENTRY(file, 0);
362        entry->voff = file->offset;
363        entry->doff = file->start;
364        entry->size = 0;
365        entry->no = file->next_chunk;
366    }
367    return;
368}
369
370static const char *
371b_pvrfifo_make_chunk_name(char *buf, size_t buf_size, const char *template, const char *file_name, unsigned chunk_no)
372{
373    BKNI_Snprintf(buf, buf_size, template,  file_name, chunk_no/64, chunk_no%64);
374    return buf;
375}
376
377static NEXUS_Error
378b_pvrfifo_remove_chunk(char *buf, size_t buf_size, const char *template, const char *file_name, unsigned chunk_no)
379{
380    NEXUS_Error rc;
381
382    BDBG_MSG(("b_pvrfifo_remove_chunk: %s removing chunk %u", file_name, chunk_no));
383    b_pvrfifo_make_chunk_name(buf, buf_size, template, file_name, chunk_no);
384    rc = unlink(buf);
385    if(rc!=0) {
386        return BERR_TRACE(NEXUS_UNKNOWN);
387    }
388    return NEXUS_SUCCESS;
389}
390
391static void
392b_pvrfifo_register_new_chunk(struct bfile_io_write_fifo *file)
393{
394    unsigned i;
395    BDBG_MSG(("b_pvrfifo_register_new_chunk: %#lx allocating chunk %u", (unsigned long)file, file->next_chunk));
396    for(i=0;i<BFIFO_N_ENTRYS;i++) {
397        if(file->header->data.h.meta.master.chunk_no[i]==BFIFO_INVALID_CHUNK) {
398            file->header->data.h.meta.master.chunk_no[i] = file->next_chunk;
399            file->header->data.h.meta.master.chunk_ref_cnt[i] = 1;
400            break;
401        }
402    }
403    if(i==BFIFO_N_ENTRYS) {
404        BDBG_ERR(("b_pvrfifo_register_new_chunk: %#lx can't allocate space for chunk no %u", (unsigned long)file, (unsigned)file->next_chunk));
405    }
406    file->next_chunk++;
407    return;
408}
409
410static void
411b_pvrfifo_write_next_chunk(struct bfile_io_write_fifo *file)
412{
413    struct bpvrfifo_entry *entry;
414    unsigned i;
415
416    for(i=0;i<BFIFO_N_ENTRYS;i++) {
417        entry = B_ENTRY(file, i);
418        if(B_ENTRY_IS_EMPTY(entry)) {
419            /* just find empty entry, and allocate new chunk */
420            entry->voff = file->offset;
421            entry->doff = 0;
422            entry->size = 0;
423            entry->no = file->next_chunk;
424            b_pvrfifo_register_new_chunk(file);
425            b_unlock(file);
426            b_pvrfifo_write_sync(file);
427            b_lock(file);
428            break;
429        }
430    }
431    return;
432}
433
434static ssize_t
435bpvrfifo_write(bfile_io_write_t fd, const void *buf_, size_t length)
436{
437    struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo*) fd;
438    ssize_t result;
439    const void *buf = buf_;
440    unsigned i;
441    struct bfile_io_write_posix *write_fd;
442
443    BDBG_ASSERT(file->header);
444    BDBG_MSG_IO(file, (">write: %s %u %lld:%u", file->header->chunked?"chunked":"", file->header->busy, file->offset, (unsigned)length ));
445    b_lock(file);
446    file->header->busy++;
447    file->header->active = true;
448
449    for(result=0;length>0;) {
450        size_t to_write = 0;
451        ssize_t rc;
452        struct bpvrfifo_entry *entry;
453        off_t boundary = 0;
454        off_t rc_off;
455
456        /* coverity[use] */
457        for(entry = (struct bpvrfifo_entry *)file->entry_cache, i=0;i<BFIFO_N_ENTRYS;) {
458            if(entry==NULL) {
459                entry = B_ENTRY(file, i);
460                i++;
461                if (B_ENTRY_IS_EMPTY(entry)) {
462                    entry = NULL;
463                    break;
464                }
465            }
466            if(entry->voff + entry->size == file->offset) {
467                boundary = file->size;
468                if(!file->header->chunked && !B_ENTRY_IS_EMPTY(&entry[1])) {
469                    boundary = entry[1].doff;
470                }
471                to_write = length;
472                if (to_write > boundary - (entry->doff + entry->size)) {
473                    to_write = boundary - (entry->doff + entry->size);
474                }
475                BDBG_MSG_IO(file, ( "to_write:%u file->size:%lld entry[1].doff:%lld entry->doff:%lld entry->size:%u", to_write, file->size, entry[1].doff, entry->doff, entry->size)); /* add this */
476                if(to_write>0) {
477                    break;
478                }
479            }
480            entry = NULL;
481        }
482        file->entry_cache = entry;
483        if (!entry) {
484            BDBG_WRN(("can't write to descriptor %#x:%lld", (unsigned)file,file->offset));
485            if(result==0) {
486                result = -1;
487            }
488            break;
489        }
490        if(file->header->chunked) {
491            write_fd = &file->chunk_data;
492            if(file->chunk_data_no != entry->no) {
493                off_t rc;
494                if(file->chunk_data_no != BFIFO_INVALID_CHUNK) {
495                    bfile_io_write_posix_close(&file->chunk_data);
496                    file->chunk_data_no = BFIFO_INVALID_CHUNK;
497                }
498                b_pvrfifo_make_chunk_name(file->chunk_name, sizeof(file->chunk_name), file->header->data.h.meta.master.chunkTemplate,  file->file_name, entry->no);
499                b_unlock(file);
500                rc = bfile_io_write_posix_open(write_fd, file->chunk_name, file->direct);
501                b_lock(file);
502                if(rc) {
503                    BDBG_WRN(("can't open file %s", file->chunk_name));
504                    if(result==0) {
505                        result = -1;
506                    }
507                    break;
508                }
509                file->chunk_data_no = entry->no;
510            }
511        } else {
512            write_fd = &file->data;
513        }
514        /* BDBG_ASSERT(boundary>0); */
515         BDBG_MSG_IO(file, (">writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf));
516         b_unlock(file);
517         rc_off = b_wseek(write_fd, entry->doff + entry->size, SEEK_SET);
518         b_lock(file);
519         BDBG_MSG_IO(file, ("wseek:%#x %lld -> %lld", entry->doff + entry->size, rc_off));
520         if (rc_off != entry->doff + entry->size) {
521             if (result==0) {
522                 if (rc_off < 0) {
523                     result = (ssize_t)rc_off; /* propagate error */
524                 } else {
525                     result = -1;
526                 }
527             }
528             break;
529         }
530         b_unlock(file);
531         rc = b_write(write_fd, buf, to_write);
532         b_lock(file);
533         BDBG_MSG_IO(file, ("<writing:%#x [%lld/%lld/%lld/%d] (%u/%u/%lld) %#x->%d", entry->voff, entry->doff, boundary, entry-B_ENTRY(file,0), (unsigned)result, (unsigned)to_write, (unsigned)length, file->offset, (unsigned)buf, (int)rc));
534         if (rc<=0) {
535             if  (result==0) {
536                 result = rc; /* propagate error */
537             }
538             break;
539         }
540         BDBG_ASSERT((size_t)rc <= to_write);
541        result += rc;
542        length -= (size_t) rc;
543        buf = (const uint8_t *)buf + rc;
544        entry->size = entry->size + rc;
545        file->offset = file->offset + rc;
546        BDBG_ASSERT(entry->doff+entry->size <= file->size);
547        if (entry->doff + entry->size == boundary) {
548            file->entry_cache = NULL;
549            if(file->header->chunked) {
550                b_pvrfifo_write_next_chunk(file);
551            } else {
552                b_pvrfifo_write_next_unit(file);
553            }
554        }
555    }
556    file->header->busy--;
557    B_DUMP_ENTRYS(file);
558    BDBG_MSG_IO(file, ("<write: %s %u %lld:%u", file->header->chunked?"chunked":"", file->header->busy, file->offset, (unsigned)length ));
559    if(file->writeSnapshotFile) {
560        bfile_fifo_write_snapshot_locked(file->writeSnapshotFile);
561        file->writeSnapshotFile = NULL;
562    }
563    b_unlock(file);
564    return result;
565}
566
567static ssize_t
568bpvrfifo_read(bfile_io_read_t fd, void *buf_, size_t length)
569{
570    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo*) fd;
571    ssize_t result;
572    void *buf = buf_;
573    unsigned i;
574    ssize_t rc;
575    struct bfile_io_read_posix *read_fd;
576
577
578    BDBG_ASSERT(file->header);
579    BDBG_MSG_IO(file, (">read:%u %lld:%u", file->header->busy, file->cur_pos, (unsigned)length));
580    b_lock(file);
581    file->header->busy++;
582    for(result=0;length>0;) {
583        off_t rc_off, seek_off;
584        size_t to_read = length;
585
586        {
587            const struct bpvrfifo_entry *entry; /* when lock is released writer could update move entries around, so protect access to the volatile storage */
588
589        if(file->trim_count != file->header->trim_count) {
590            file->trim_count = file->header->trim_count;
591            file->entry_cache = NULL;
592        }
593
594        for(entry=file->entry_cache,i=0;i<BFIFO_N_ENTRYS;) {
595            if(entry==NULL) {
596                entry = B_ENTRY(file,i);
597                i++;
598                if (B_ENTRY_IS_EMPTY(entry)) {
599                    entry = NULL;
600                    break;
601                }
602            }
603            if( entry->voff <= file->cur_pos &&
604                entry->voff + entry->size > file->cur_pos) {
605                to_read = length;
606                if (to_read > entry->size - (file->cur_pos - entry->voff)) {
607                    to_read =  entry->size - (file->cur_pos - entry->voff);
608                }
609                if(to_read > 0) {
610                    break;
611                }
612            }
613            entry = NULL;
614        }
615        file->entry_cache = (struct bpvrfifo_entry *)entry;
616        if (!entry) {
617            if (result==0) {
618                if (B_ENTRY(file, 0)->voff > file->cur_pos) {
619                    B_DUMP_ENTRY(file,0);
620                    B_DUMP_ENTRY(file,1);
621                    BDBG_WRN(("bpvrfifo_read: out of bounds offset %#x,%lld", (unsigned)file,file->cur_pos));
622                    result = -1;
623                }
624            }
625            break;
626        }
627        if(file->header->chunked) {
628            read_fd = &file->chunk_data;
629            if(file->chunk_data_no != entry->no) {
630                NEXUS_Error rc;
631                if(file->chunk_data_no != BFIFO_INVALID_CHUNK) {
632                    bfile_io_read_posix_close(&file->chunk_data);
633                    file->chunk_data_no = BFIFO_INVALID_CHUNK;
634                }
635                b_pvrfifo_make_chunk_name(file->chunk_name, sizeof(file->chunk_name), file->chunkTemplate,  file->master_name, entry->no);
636                b_unlock(file);
637                rc = bfile_io_read_posix_open(read_fd, file->chunk_name, file->direct);
638                b_lock(file);
639                if(rc!=NEXUS_SUCCESS) {
640                    BDBG_WRN(("can't open file %s", file->chunk_name));
641                    if(result==0) {
642                        result = -1;
643                    }
644                    break;
645                }
646                file->chunk_data_no = entry->no;
647            }
648        } else {
649            read_fd = &file->data;
650        }
651        seek_off = entry->doff + (file->cur_pos - entry->voff);
652        BDBG_MSG_IO(file, (">reading: [%lld/%lld/%d -> %lld] (%u/%u/%u/%lld) %#x", entry->voff, entry->doff, entry-B_ENTRY(file,0), seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf));
653        }
654        b_unlock(file);
655        rc_off = b_rseek(read_fd, seek_off, SEEK_SET);
656        b_lock(file);
657        BDBG_MSG_IO(file, ("rseek: %lld -> %lld", seek_off, rc_off));
658        if (rc_off != seek_off) {
659            if (result==0) {
660                if (rc_off < 0) {
661                    result = (ssize_t)rc_off; /* propagate error */
662                } else {
663                    BDBG_WRN(("bpvrfifo_read: %#lx can't seek to %lld(instead %lld)", (unsigned long)file, seek_off, rc_off));
664                    result = -1;
665                }
666            }
667            break;
668        }
669        b_unlock(file);
670        rc = b_read(read_fd, buf, to_read);
671        b_lock(file);
672        BDBG_MSG_IO(file, ("<reading: %lld (%u/%u/%u/%lld) %#x->%d", seek_off, (unsigned)result, (unsigned)to_read, (unsigned)length, file->cur_pos, (unsigned)buf, (int)rc));
673        if (rc!=(ssize_t)to_read) {
674            if (result==0) {
675                result = rc; /* propagate error */
676            }
677            break;
678        }
679        BDBG_ASSERT((size_t)rc <= to_read);
680        result += rc;
681        buf = (uint8_t *)buf + rc;
682        length -= (size_t) rc;
683        file->cur_pos = file->cur_pos + rc;
684    }
685    file->header->busy--;
686    B_DUMP_ENTRYS(file);
687    BDBG_MSG_IO(file, ("<read:%u %lld:%u=%d", file->header->busy, file->cur_pos, (unsigned)length, (int)result));
688
689    b_unlock(file);
690    return result;
691}
692
693
694static int
695bpvrfifo_bounds_locked(const struct bfile_io_read_fifo *file, off_t *first, off_t *last)
696{
697    unsigned i;
698
699    BDBG_ASSERT(file->header);
700
701    if (B_ENTRY_IS_EMPTY(B_ENTRY(file,0))) {
702        *first = *last = 0;
703    } else {
704        *first = B_ENTRY(file,0)->voff;
705        *last = B_ENTRY(file,0)->voff + B_ENTRY(file,0)->size;
706    }
707
708    for(i=1;i<BFIFO_N_ENTRYS;i++) {
709        if (B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) {
710            break;
711        }
712        if(B_ENTRY(file,i)->voff >= *last) {
713            *last = B_ENTRY(file,i)->voff + B_ENTRY(file,i)->size;
714        }
715        if(B_ENTRY(file,i)->voff < *first) {
716            *first = B_ENTRY(file,i)->voff;
717        }
718    }
719
720    if( file->header->trim_gap ) {
721        *first += (off_t)(file->header->trim_gap);
722    }
723
724    return 0;
725}
726
727static int
728bpvrfifo_bounds(bfile_io_read_t fd, off_t *first, off_t *last )
729{
730    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd;
731    int rc;
732
733    BDBG_ASSERT(file->header);
734    b_lock(file); /* don't need to set busy because lock isn't released */
735
736    BDBG_MSG_IO(file, (">bounds"));
737    rc = bpvrfifo_bounds_locked(file, first, last);
738    BDBG_MSG_IO(file, ("<bounds: %lld..%lld", *first, *last));
739    b_unlock(file);
740    return rc;
741}
742
743static off_t
744bpvrfifo_trim(bfile_io_write_t fd, off_t trim_pos)
745{
746    struct bfile_io_write_fifo *file = (struct bfile_io_write_fifo *) fd;
747    off_t result;
748    unsigned i,j;
749    struct bpvrfifo_entry *entry;
750    bool dirty = false;
751
752    BDBG_ASSERT(file->header);
753    b_lock(file);
754    BDBG_MSG_IO(file, (">trim:%u %lld", file->header->busy, trim_pos));
755    file->header->active = true;
756    result = 0;
757    if (file->header->busy) {
758        goto done;
759    }
760
761    /* trim_pos = (trim_pos) & (~(4096-1)); */
762    if (trim_pos>file->offset) {
763        trim_pos = file->offset;
764    } else if (trim_pos<0) {
765        trim_pos = 0;
766    }
767
768    for(i=0;i<BFIFO_N_ENTRYS;i++) {
769        entry = B_ENTRY(file,i);
770
771        if (B_ENTRY_IS_EMPTY(entry)) {
772            break;
773        } else if( entry->voff >= trim_pos) {
774            continue;
775        } else if (entry->voff + entry->size > trim_pos ) {
776            entry->size -= trim_pos - entry->voff;
777            entry->doff += trim_pos - entry->voff;
778            entry->voff = trim_pos;
779            result = trim_pos;
780        } else {
781            if (result < entry->voff + entry->size) {
782                result = entry->voff + entry->size;
783            }
784            if(file->header->chunked) {
785                /* close current chunk */
786                if(file->chunk_data_no == entry->no) {
787                    bfile_io_write_posix_close(&file->chunk_data);
788                    file->chunk_data_no = BFIFO_INVALID_CHUNK;
789                }
790                /* XXX it's posible that readers still have chunk opened */
791                for(j=0;j<BFIFO_N_ENTRYS;j++) {
792                     if(file->header->data.h.meta.master.chunk_no[j]==entry->no) {
793                        /* bingo found chunk */
794                        if(file->header->data.h.meta.master.chunk_ref_cnt[j]>0) {
795                            file->header->data.h.meta.master.chunk_ref_cnt[j]--;
796                            if(file->header->data.h.meta.master.chunk_ref_cnt[j]==0) {
797                                b_pvrfifo_remove_chunk(file->chunk_name, sizeof(file->chunk_name), file->header->data.h.meta.master.chunkTemplate,  file->file_name, entry->no);
798                                file->header->data.h.meta.master.chunk_no[j]=BFIFO_INVALID_CHUNK;
799                            }
800                        }
801                        break;
802                     }
803                }
804                if(j==BFIFO_N_ENTRYS) {
805                    BDBG_ERR(("bpvrfifo_trim: %#lx unknown chunk no %u", (unsigned long)file, (unsigned)entry->no));
806                }
807            }
808            dirty = true;
809            B_ENTRY_CLEAR(B_ENTRY(file,i)); /* mark entry as unused */
810        }
811    }
812    /* collapse empty entries */
813    for(i=0;i<BFIFO_N_ENTRYS;i++) {
814        if (B_ENTRY_IS_EMPTY(B_ENTRY(file,i))) {
815            for(j=i+1;j<BFIFO_N_ENTRYS;j++) {
816                if (!B_ENTRY_IS_EMPTY(B_ENTRY(file,j))) {
817                    *B_ENTRY(file, i) = *B_ENTRY(file, j);
818                    B_ENTRY_CLEAR(B_ENTRY(file, j));
819                    break;
820                }
821            }
822            if (j==BFIFO_N_ENTRYS) {
823                break;
824            }
825        }
826    }
827    entry = B_ENTRY(file, 0);
828    if(file->header->chunked) {
829        if (B_ENTRY_IS_EMPTY(entry)) {
830            entry->doff = 0;
831            entry->voff = result;
832            entry->size = 0;
833            entry->no = file->next_chunk;
834            b_pvrfifo_register_new_chunk(file);
835            dirty = true;
836        }
837    } else {
838        if (B_ENTRY_IS_EMPTY(entry)) {
839            /* file was trimed to  bones, create new entry */
840            entry->doff = file->start;
841            entry->voff = result;
842            entry->size = 0;
843            entry->no = file->next_chunk;
844        }
845    }
846done:
847    B_DUMP_ENTRYS(file);
848    file->entry_cache = NULL;
849    file->header->trim_count++;
850    BDBG_MSG_IO(file, ("<trim:%u %lld", file->header->busy, result));
851    if(dirty && file->header->chunked) {
852        /* XXX write to the file with acquired lock */
853        b_pvrfifo_write_sync(file);
854    }
855    b_unlock(file);
856    return result;
857}
858
859static off_t
860bpvrfifo_seek(bfile_io_read_t fd, off_t offset, int whence)
861{
862    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *) fd;
863    off_t size,begin;
864    int rc;
865
866    BDBG_MSG_IO(file,(">seek: %lld %d", offset, whence));
867    b_lock(file);
868
869    if (whence==SEEK_CUR && offset==0) {
870        /* special case, which is used to  rerrieve current position, without bound checking  */
871        offset = file->cur_pos;
872        goto done;
873    }
874    rc = bpvrfifo_bounds_locked(file, &begin, &size);
875    if (rc<0) {
876        offset = -1;
877        goto error;
878    }
879    /* locate where file begins */
880    switch(whence) {
881    case SEEK_CUR:
882        offset = file->cur_pos + offset;
883        break;
884    case SEEK_END:
885        offset = size + offset;
886        break;
887    case SEEK_SET:
888        break;
889    default:
890        BDBG_ERR(("unknown seek whence %d", whence));
891        goto error;
892    }
893    if (offset == file->cur_pos) {
894        goto done;
895    }
896    if (offset < 0 || offset >= size) {
897        BDBG_WRN(("<seek out out bounds 0..%lld..%lld", offset, size));
898        offset = -1;
899        goto error;
900    }
901    if (offset < begin) {
902        offset = begin;
903    }
904
905    /* just assign new offset */
906done:
907    file->cur_pos = offset;
908error:
909    BDBG_MSG_IO(file, ("<seek: %lld", offset));
910    b_unlock(file);
911    return offset;
912}
913
914static const struct bfile_io_write bpvrfifo_io_write = {
915    bpvrfifo_write,
916    bpvrfifo_trim,
917    BIO_DEFAULT_PRIORITY
918};
919
920static const struct bfile_io_read bpvrfifo_io_read = {
921    bpvrfifo_read,
922    bpvrfifo_seek,
923    bpvrfifo_bounds,
924    BIO_DEFAULT_PRIORITY
925};
926
927static void
928b_pvrfifo_header_init(struct bpvrfifo_header *header)
929{
930    BDBG_ASSERT(header);
931    BDBG_CASSERT(sizeof(header->data) == sizeof(header->data.buf)); /* for proper aligment, size of the header shall be equal to size of the buffer */
932    BKNI_Memset(header,0,sizeof(*header));
933    header->data.h.signature = bpvrfifo_signature;
934    header->busy = 0;
935    header->prev_trim = 0;
936    header->trim_gap = 0;
937    header->trim_count = 0;
938    header->chunked = false;
939    header->active = false;
940    return;
941}
942
943
944
945int
946b_file_strcpy(char *dest, size_t buf_len, const char *src)
947{
948    return BKNI_Snprintf(dest, buf_len, "%s", src);
949}
950
951static struct bfile_io_write_fifo *
952bpvrfifo_write_open(const char *fname, bool direct, off_t start, struct bfile_io_write_fifo *meta, off_t meta_offset )
953{
954    struct bfile_io_write_fifo *file =  BKNI_Malloc(sizeof(*file));
955    BERR_Code rc;
956    unsigned i;
957
958    if (!file) {
959        BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
960        goto err_alloc;
961    }
962    if(meta==NULL) {
963        meta = file;
964    }
965    BKNI_Memset(file, 0, sizeof(*file));
966    file->direct = direct;
967    file->header = &file->_header;
968    file->meta = meta;
969    file->meta_offset = meta_offset;
970    file->meta_size = 0;
971    b_pvrfifo_header_init(file->header);
972    file->writeSnapshotFile = NULL;
973    rc = BKNI_CreateMutex(&file->header->lock);
974    if (rc!=BERR_SUCCESS) {
975        goto err_lock;
976    }
977
978    file->data = file->data_;
979    file->chunk_data = file->chunk_data_;
980    file->chunk_data_no = BFIFO_INVALID_CHUNK; /* clear chunk file */
981    rc = bfile_io_write_posix_open(&file->data, fname, direct);
982    if(rc!=NEXUS_SUCCESS) { goto err_open_data; }
983    /* initialize data */
984    file->self = bpvrfifo_io_write;
985    file->start = start;
986    file->ref_cnt = 1;
987    file->next_chunk = 0;
988    file->entry_cache = NULL;
989    file->size = 512 * 1024;
990    file->header->data.h.type = bpvrfifo_type_unit;
991    BKNI_Memcpy(file->header->data.h.meta.master.chunkTemplate, b_file_chunkTemplate, sizeof(b_file_chunkTemplate));
992    b_file_strcpy(file->file_name, sizeof(file->file_name), fname); /* save filename for further use */
993    for(i=0;i<BFIFO_N_ENTRYS;i++) {
994        B_ENTRY_CLEAR(B_ENTRY(file, i));
995        file->header->data.h.meta.master.chunk_no[i] = BFIFO_INVALID_CHUNK;
996        file->header->data.h.meta.master.chunk_ref_cnt[i] = 0;
997    }
998    B_ENTRY_CLEAR(B_ENTRY(file, BFIFO_N_ENTRYS));
999    B_ENTRY(file, 0)->doff = file->start;
1000    B_ENTRY(file, 0)->no = 0;
1001    return file;
1002
1003err_open_data:
1004    BKNI_DestroyMutex(file->header->lock);
1005err_lock:
1006    BKNI_Free(file);
1007err_alloc:
1008    return NULL;
1009}
1010
1011static bfile_io_write_t
1012bpvrfifo_write_file(struct bfile_io_write_fifo *file)
1013{
1014    return &file->self;
1015}
1016
1017/* decrement reference counter and once it reaches 0 then release memory */
1018static void
1019bpvrfifo_write_release(struct bfile_io_write_fifo *file)
1020{
1021    bool last;
1022
1023    b_lock(file);
1024    BDBG_ASSERT(file->header);
1025    BDBG_MSG_IO(file, ("release:%u:%u", file->ref_cnt, file->header->busy));
1026    BDBG_ASSERT(file->ref_cnt);
1027    file->ref_cnt--;
1028    last = file->ref_cnt==0;
1029    BDBG_ASSERT(!last || file->header->busy==0);
1030    b_unlock(file);
1031    if (last) {
1032        BKNI_DestroyMutex(file->header->lock);
1033        BKNI_Free(file);
1034    }
1035    return;
1036}
1037
1038static void
1039bpvrfifo_write_close(struct bfile_io_write_fifo *file)
1040{
1041    bfile_io_write_posix_close(&file->data);
1042    bpvrfifo_write_release(file);
1043    return;
1044}
1045
1046static struct bfile_io_read_fifo *
1047bpvrfifo_read_open(const char *fname, bool direct, struct bfile_io_write_fifo *writer, struct bfile_io_read_fifo *meta, off_t meta_off)
1048{
1049    struct bfile_io_read_fifo *file =  BKNI_Malloc(sizeof(*file));
1050    NEXUS_Error rc;
1051
1052    if (!file) {
1053        rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
1054        goto err_alloc;
1055    }
1056    if(meta==NULL) {
1057        meta = file;
1058    }
1059    file->direct = direct;
1060    file->entry_cache = NULL;
1061    file->trim_count = 0;
1062    file->data = file->data_;
1063    file->chunk_data = file->chunk_data_;
1064    file->chunk_data_no = BFIFO_INVALID_CHUNK;
1065    rc = bfile_io_read_posix_open(&file->data, fname, direct);
1066    if (rc!=NEXUS_SUCCESS) { rc = BERR_TRACE(rc); goto err_open_data; }
1067    file->writer = writer;
1068    if (writer) {
1069        b_lock(writer);
1070        writer->ref_cnt++;
1071        file->header = writer->header;
1072        file->chunkTemplate = writer->header->data.h.meta.master.chunkTemplate;
1073        BKNI_Memcpy(file->master_name, writer->file_name, sizeof(file->master_name));
1074        b_unlock(writer);
1075    } else {
1076        BERR_Code rc;
1077        void *buf;
1078        off_t rc_off;
1079        ssize_t p_rc;
1080
1081        file->header = BKNI_Malloc(sizeof(*file->header));
1082        if(!file->header) {
1083            BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
1084            goto err_hdr_alloc;
1085        }
1086        b_pvrfifo_header_init(file->header);
1087        rc = BKNI_CreateMutex(&file->header->lock);
1088        if (rc!=BERR_SUCCESS) {
1089            BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
1090            goto err_lock;
1091        }
1092        rc_off = b_rseek(&meta->data, meta_off, SEEK_SET);
1093        if(rc_off!=meta_off) {
1094            BERR_TRACE(NEXUS_UNKNOWN);
1095            goto err_rseek;
1096        }
1097        buf = &file->header->data;
1098        p_rc = b_read(&meta->data, buf, sizeof(file->header->data));
1099        if (p_rc!=sizeof(file->header->data) || BKNI_Memcmp(&file->header->data.h.signature, &bpvrfifo_signature, sizeof(bpvrfifo_signature))!=0) {
1100            BERR_TRACE(NEXUS_INVALID_PARAMETER);
1101            goto err_meta;
1102        }
1103        file->header->chunked = file->header->data.h.type != bpvrfifo_type_unit;
1104        if(file->header->data.h.type == bpvrfifo_type_snapshot) {
1105            BKNI_Memcpy(file->master_name, file->header->data.h.meta.snapshot.master_file, sizeof(file->master_name));
1106            file->chunkTemplate = file->header->data.h.meta.snapshot.chunkTemplate;
1107        } else {
1108            b_file_strcpy(file->master_name, sizeof(file->master_name), fname);
1109            file->chunkTemplate = file->header->data.h.meta.master.chunkTemplate;
1110        }
1111    }
1112    file->self = bpvrfifo_io_read;
1113    return  file;
1114
1115err_meta:
1116err_rseek:
1117err_lock:
1118    if(!writer) {
1119        BKNI_Free(file->header);
1120    }
1121err_hdr_alloc:
1122    bfile_io_read_posix_close(&file->data);
1123err_open_data:
1124    BKNI_Free(file);
1125err_alloc:
1126    return NULL;
1127}
1128
1129static bfile_io_read_t
1130bpvrfifo_read_file(struct bfile_io_read_fifo *file)
1131{
1132    return &file->self;
1133}
1134
1135
1136static void
1137bpvrfifo_read_close(struct bfile_io_read_fifo *file)
1138{
1139    bfile_io_read_posix_close(&file->data);
1140    if(file->writer) {
1141        bpvrfifo_write_release(file->writer);
1142    } else {
1143        BKNI_DestroyMutex(file->header->lock);
1144        BKNI_Free(file->header);
1145    }
1146    BKNI_Free(file);
1147    return;
1148}
1149
1150#define B_TRIM_TIMER    5000
1151#define B_TRIM_TRY_TIMER    30
1152
1153struct bfile_out_desc {
1154    struct bfile_io_write_fifo *file;
1155    unsigned trim_count;
1156    off_t trim_off;
1157};
1158
1159struct NEXUS_ChunkedFifoRecord {
1160    struct NEXUS_FileRecord self;
1161    struct bfile_out_desc data;
1162    struct bfile_out_desc index;
1163    struct bfile_io_read_fifo *rd_index;
1164    unsigned index_entrysize;
1165    BNAV_Player_Handle bcm_player;
1166    NEXUS_TimerHandle timer; /* currently active timer  or NULL */
1167    NEXUS_Time lastSnapshotTime;
1168    NEXUS_ChunkedFifoRecordSettings cfg;
1169};
1170
1171struct bfile_in_fifo {
1172    struct NEXUS_FilePlay self;
1173    struct bfile_io_read_fifo *data;
1174    struct bfile_io_read_fifo *index;
1175    struct NEXUS_ChunkedFifoRecord *writer;
1176};
1177
1178#define GET_INDEX_FILEIO(fp) (&((NEXUS_ChunkedFifoRecordHandle) fp)->rd_index->self)
1179
1180static long
1181bp_read(void *buffer, long size, long count, void *fp )
1182{
1183    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
1184
1185    return (long)f->read(f, buffer, (size_t)(count*size));
1186}
1187
1188static long
1189bp_tell( void *fp )
1190{
1191    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
1192    return (long)f->seek(f, 0, SEEK_CUR);
1193}
1194
1195#if 0
1196static int
1197bp_seek( void *fp, long offset, int origin )
1198{
1199    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
1200    off_t rc;
1201    rc = f->seek(f, (off_t)offset, origin);
1202    if ( rc == (off_t)-1) {
1203        return -1;
1204    }
1205    return 0;
1206}
1207#endif
1208
1209static int
1210bp_bounds(BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex)
1211{
1212    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
1213    off_t first, last;
1214    unsigned index_entrysize =((NEXUS_ChunkedFifoRecordHandle)fp)->index_entrysize;
1215
1216    f->bounds(f, &first, &last);
1217
1218    BSTD_UNUSED(handle);
1219    *firstIndex = first/index_entrysize;
1220    *lastIndex = (last-1)/index_entrysize;
1221
1222    return 0;
1223}
1224
1225static int
1226trim_bp_bounds( BNAV_Player_Handle handle, void *fp, long *firstIndex, long *lastIndex )
1227{
1228    bfile_io_read_t fd = GET_INDEX_FILEIO(fp);
1229    off_t first, last;
1230    unsigned index_entrysize =((NEXUS_ChunkedFifoRecordHandle)fp)->index_entrysize;
1231    int rc;
1232
1233    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)fd;
1234    BDBG_ASSERT(file->header);
1235    b_lock(file);
1236    rc = bpvrfifo_bounds_locked(file, &first, &last );
1237    if( file->header->trim_gap ) {
1238        /* Untrimmed file start is first offset minus trim gap */
1239        first -= (off_t)(file->header->trim_gap);
1240    }
1241    b_unlock(file);
1242
1243
1244    BSTD_UNUSED(handle);
1245    *firstIndex = first/index_entrysize;
1246    *lastIndex = (last-1)/index_entrysize;
1247
1248    return 0;
1249}
1250
1251static int
1252trim_bp_seek( void *fp, long offset, int origin )
1253{
1254    bfile_io_read_t f = GET_INDEX_FILEIO(fp);
1255    unsigned index_entrysize =((NEXUS_ChunkedFifoRecordHandle)fp)->index_entrysize;
1256    long saveOffset = 0;
1257    struct bfile_io_read_fifo *file = (struct bfile_io_read_fifo *)f;
1258    off_t rc;
1259
1260    if( file->header->trim_gap ) {
1261        BNAV_Player_Handle dummyHandle = NULL;
1262        long firstIdx, lastIdx;
1263
1264        /* Find beginning trimmed area */
1265        trim_bp_bounds( dummyHandle, fp, &firstIdx, &lastIdx );
1266        saveOffset = firstIdx*index_entrysize;
1267
1268        if( offset && offset < firstIdx*(int)index_entrysize ) {
1269            /* But don't adjust for a tell request ( offset=0 , origin=SEEK_SET ) */
1270            offset = firstIdx*index_entrysize;
1271        }
1272    }
1273
1274    rc = f->seek(f, (off_t)offset, origin);
1275    if ( rc == (off_t)-1) {
1276        return -1;
1277    }
1278
1279
1280    if ( offset==0 && saveOffset ) {
1281        /* Fix up cur_pos to actual trim area beginning */
1282        b_lock(file);
1283        file->cur_pos = saveOffset;
1284        b_unlock(file);
1285    }
1286    else if ( offset < file->cur_pos ) {
1287        /* If get in here , it means trimming is happening */
1288        b_lock(file);
1289        file->cur_pos = offset;
1290        b_unlock(file);
1291    }
1292
1293    return 0;
1294}
1295
1296
1297static void
1298bfile_fifo_close_in(NEXUS_FilePlayHandle f)
1299{
1300    struct bfile_in_fifo *file =  (struct bfile_in_fifo *)f;
1301
1302    BDBG_ASSERT(file->data);
1303    BDBG_ASSERT(file->index);
1304    bpvrfifo_read_close(file->data);
1305    bpvrfifo_read_close(file->index);
1306    BKNI_Free(file);
1307    return;
1308}
1309
1310NEXUS_FilePlayHandle
1311NEXUS_ChunkedFifoPlay_Open(const char *fname, const char *indexname, NEXUS_ChunkedFifoRecordHandle writer)
1312{
1313    struct bfile_in_fifo *file;
1314    NEXUS_Error rc;
1315
1316    if (fname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
1317    if (indexname==NULL) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
1318
1319    file = BKNI_Malloc(sizeof(*file));
1320    if (!file) { rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY); goto err_alloc; }
1321    BKNI_Memset(file, 0, sizeof(*file));
1322
1323    file->index = bpvrfifo_read_open(indexname, false, writer?writer->index.file:NULL, NULL, 0);
1324    if (!file->index) { goto err_index;}
1325
1326    file->data = bpvrfifo_read_open(fname, true, writer?writer->data.file:NULL, file->index, sizeof(file->index->header->data));
1327    if (!file->data) { goto err_data;}
1328
1329    if (writer==NULL) {
1330        struct bpvrfifo_header *buf;
1331        ssize_t rc;
1332
1333        buf = file->index->header;
1334        b_rseek(&file->index->data, 0, SEEK_SET);
1335        rc = b_read(&file->index->data, &buf->data, sizeof(buf->data));
1336        if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) {
1337            rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1338            goto err_meta;
1339        }
1340
1341        buf = file->data->header;
1342        b_rseek(&file->index->data, sizeof(buf->data), SEEK_SET);
1343        rc = b_read(&file->index->data, buf, sizeof(buf->data));
1344        if (rc!=sizeof(buf->data) || buf->data.h.signature.signature[0]!=bpvrfifo_signature.signature[0]) {
1345            rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1346            goto err_meta;
1347        }
1348    }
1349
1350    file->self.file.index = bpvrfifo_read_file(file->index);
1351    file->self.file.data = bpvrfifo_read_file(file->data);
1352
1353    file->self.file.close = bfile_fifo_close_in;
1354
1355    return &file->self;
1356
1357err_meta:
1358    bpvrfifo_read_close(file->data);
1359err_data:
1360    bpvrfifo_read_close(file->index);
1361err_index:
1362    BKNI_Free(file);
1363err_alloc:
1364    return NULL;
1365}
1366
1367static void
1368bfile_fifo_write_snapshot_locked(struct NEXUS_ChunkedFifoRecord *file)
1369{
1370    const struct bpvrfifo_header *buf;
1371
1372    buf = file->index.file->header;
1373    b_wseek(&file->index.file->data, 0, SEEK_SET);
1374    b_write(&file->index.file->data, &buf->data, sizeof(buf->data));
1375
1376    buf = file->data.file->header;
1377    b_wseek(&file->index.file->data, sizeof(buf->data), SEEK_SET);
1378    b_write(&file->index.file->data, &buf->data, sizeof(buf->data));
1379    return;
1380}
1381
1382static void
1383bfile_fifo_close_out(NEXUS_FileRecordHandle f)
1384{
1385    struct NEXUS_ChunkedFifoRecord *file =  (struct NEXUS_ChunkedFifoRecord *)f;
1386
1387    if (file->timer) {
1388        NEXUS_CancelTimer(file->timer);
1389    }
1390    if (file->bcm_player) {
1391        BNAV_Player_Close(file->bcm_player);
1392    }
1393
1394    b_lock(file->index.file);
1395    bfile_fifo_write_snapshot_locked(file);
1396    bfile_fifo_write_snapshot_locked(file);
1397    b_unlock(file->index.file);
1398
1399    bpvrfifo_read_close(file->rd_index);
1400    bpvrfifo_write_close(file->data.file);
1401    bpvrfifo_write_close(file->index.file);
1402    BKNI_Free(file);
1403    return;
1404}
1405
1406static void
1407b_trim_try_player(NEXUS_ChunkedFifoRecordHandle file)
1408{
1409    if (file->bcm_player==NULL) {
1410        BNAV_DecoderFeatures features = {1,1,1,1};
1411        BNAV_Player_Settings cfg;
1412
1413        BNAV_Player_GetDefaultSettings(&cfg);
1414
1415        cfg.videoPid = 0x1FFF; /* since BNAV_Player doesn't like 0 */
1416        cfg.filePointer = file;
1417        cfg.normalPlayBufferSize = 1024*128;
1418        cfg.decoderFeatures = features;
1419        cfg.readCb = bp_read;
1420        cfg.tellCb = bp_tell;
1421        cfg.seekCb   = trim_bp_seek;
1422        cfg.boundsCb = trim_bp_bounds;
1423        cfg.transportTimestampEnabled = false;
1424        if (BNAV_Player_Open(&file->bcm_player, &cfg)!=0) {
1425            return;
1426        }
1427        BNAV_Player_GetSettings(file->bcm_player, &cfg);
1428        file->index_entrysize = BNAV_GetEntrySize(cfg.navVersion);
1429    }
1430    return;
1431}
1432
1433/* this functions return true if trim was successfull and false otherwise */
1434static bool
1435b_try_trim_file(struct bfile_out_desc *desc)
1436{
1437    off_t rc;
1438
1439    if (desc->trim_count==0) {
1440        return true;
1441    }
1442    if (desc->trim_off>0) {
1443        BDBG_MSG((">try_trim %#x:%u %lld", (unsigned)desc->file, desc->trim_count, desc->trim_off));
1444        rc = desc->file->self.trim(&desc->file->self, desc->trim_off);
1445        BDBG_MSG(("<try_trim %#x:%u %lld:%lld", (unsigned)desc->file, desc->trim_count, desc->trim_off, rc));
1446        if (rc == 0) {
1447            desc->trim_count++;
1448            return false;
1449        }
1450        if (rc<0) {
1451            BDBG_WRN(("trim has failed"));
1452            return true;
1453        }
1454    }
1455    desc->trim_count = 0;
1456    return true;
1457}
1458
1459#define B_GET_OFF_T(p) ((p)->offsetLo|(((uint64_t)(p)->offsetHi)<<32))
1460
1461/* this function called from the timer context */
1462static void
1463b_trim_timer(void *file_)
1464{
1465    NEXUS_ChunkedFifoRecordHandle file = file_;
1466    unsigned timeout = B_TRIM_TIMER;
1467    long firstIndex, lastIndex;
1468    BNAV_Player_Position first, last;
1469    int rc;
1470    unsigned long interval;
1471    NEXUS_Time start, stop;
1472
1473    NEXUS_Time_Get(&start);
1474    if(file->cfg.snapshotInterval != 0 && (NEXUS_Time_Diff(&start, &file->lastSnapshotTime)/1000)>=(long)file->cfg.snapshotInterval) {
1475        b_lock(file->index.file);
1476        file->index.file->writeSnapshotFile = file; /* we can't write data right there since it could overlap with running write operation and would corrupt the file write pointer */
1477        b_unlock(file->index.file);
1478        file->lastSnapshotTime = start;
1479    }
1480    if (file->index.trim_count || file->data.trim_count) {
1481        /* trim index first */
1482        if (!b_try_trim_file(&file->index)) {
1483            timeout = B_TRIM_TRY_TIMER;
1484            goto done;
1485        }
1486        if (!b_try_trim_file(&file->data)) {
1487            timeout = B_TRIM_TRY_TIMER;
1488            goto done;
1489        }
1490        /* this effectively limits rate of succesfull trims to one each B_TRIM_TIMER */
1491        goto done;
1492    }
1493
1494    b_trim_try_player(file);
1495    if(file->bcm_player==NULL) {
1496        BDBG_WRN(("index file is empty, trim can't be activated"));
1497        goto done;
1498    }
1499    rc = trim_bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex);
1500    if (rc!=0) {
1501        BDBG_WRN(("can't obtain file bounds"));
1502        goto done;
1503    }
1504    rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &first);
1505    if (rc!=0) {
1506        BDBG_WRN(("can't obtain first position "));
1507        rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex+1, &first);
1508        if (rc!=0) {
1509            BDBG_WRN(("..2nd Attempt also failed !"));
1510            goto done;
1511        }
1512    }
1513    rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &last);
1514    if (rc!=0) {
1515        BDBG_WRN(("can't obtain last position"));
1516        goto done;
1517    }
1518
1519    BDBG_INSTANCE_MSG(file, ("position %ld:%lu:%lld %ld:%lu:%lld ",
1520        firstIndex, first.timestamp,B_GET_OFF_T(&first), lastIndex, last.timestamp, B_GET_OFF_T(&last)));
1521
1522    interval = file->cfg.interval*1000;
1523
1524    if (last.timestamp - first.timestamp > interval) {
1525        long index;
1526        off_t off;
1527
1528        index = BNAV_Player_FindIndexFromTimestamp(file->bcm_player, last.timestamp - interval);
1529        if (index<0) {
1530            BDBG_WRN(("can't obtain new index"));
1531            goto done;
1532        }
1533        last = first; /* needed for debuging to save previous first */
1534        rc = BNAV_Player_GetPositionInformation(file->bcm_player, index, &first);
1535        if (rc!=0) {
1536            BDBG_WRN(("can't obtain new position"));
1537            goto done;
1538        }
1539        BDBG_MSG(("trimming from %d:%u:%lld to %d:%u:%lld", last.index, last.timestamp, B_GET_OFF_T(&last), index, first.timestamp, B_GET_OFF_T(&first)));
1540        off = index*file->index_entrysize;
1541        BDBG_MSG(("trimming index old %lld new %lld", (int64_t)file->index.trim_off, (int64_t)off));
1542        file->index.trim_off = off;
1543        file->index.trim_count = 1;
1544
1545        file->index.file->header->trim_gap = (index - file->index.file->header->prev_trim)*file->index_entrysize;
1546
1547        file->index.file->header->prev_trim = last.index;
1548
1549        off = B_GET_OFF_T(&first);
1550#ifdef DIRECT_IO_SUPPORT
1551        off -= off % B_DATA_ALIGN;
1552#endif
1553        BDBG_MSG(("trimming data old %lld new %lld", (int64_t)file->data.trim_off, (int64_t)off));
1554        file->data.trim_off = off;
1555        file->data.trim_count = 1;
1556
1557        timeout = B_TRIM_TRY_TIMER; /* do a trim on the next timer callout */
1558    }
1559done:
1560    file->timer = NEXUS_ScheduleTimer(timeout, b_trim_timer, file);  /* schedulle another heartbeat for the trim */
1561    NEXUS_Time_Get(&stop);
1562    BDBG_MSG(("trim_timer(%#x) %ldms", (unsigned)file , NEXUS_Time_Diff(&stop, &start)));
1563
1564    if (!file->timer) {
1565        BDBG_ERR(("trim hearbeat has died"));
1566        return;
1567    }
1568
1569    return;
1570}
1571
1572
1573NEXUS_ChunkedFifoRecordHandle
1574NEXUS_ChunkedFifoRecord_Create(const char *fname, const char *indexname)
1575{
1576    NEXUS_ChunkedFifoRecordHandle file;
1577    NEXUS_Error rc;
1578
1579    if (fname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
1580    if (indexname==NULL) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); return NULL; }
1581
1582    file = BKNI_Malloc(sizeof(*file));
1583    if (!file) { rc=BERR_TRACE(NEXUS_INVALID_PARAMETER); goto err_alloc; }
1584
1585    BKNI_Memset(file, 0, sizeof *file);
1586
1587    file->cfg.interval = 30;
1588    file->cfg.snapshotInterval = 0;
1589    file->cfg.data.soft = 512*1024*1024;
1590    file->cfg.data.hard = 1024*1024*1024;
1591    file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN;
1592    file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN;
1593    file->cfg.index.soft = 4*1024*1024;
1594    file->cfg.index.hard = 8*1024*1024;
1595
1596    file->cfg.index.chunkSize = 0;
1597    BKNI_Memcpy(file->cfg.chunkTemplate, b_file_chunkTemplate, sizeof(b_file_chunkTemplate));
1598
1599    file->data.trim_count = 0;
1600
1601    NEXUS_Time_Get(&file->lastSnapshotTime);
1602
1603    /* we save meta data in the index file, it's used because data usually is O_DIRECT, e.g. meta writes are slower and it puts constraints on the alligment of in memory meta buffer */
1604    file->data.file = bpvrfifo_write_open(fname, true, 0, file->index.file, sizeof(file->index.file->header->data));
1605    if (!file->data.file) { goto err_data;}
1606    file->data.file->size = file->cfg.data.soft;
1607
1608    file->index.trim_count = 0;
1609    file->index.file = bpvrfifo_write_open(indexname, false, 2*sizeof(file->data.file->header->data), NULL, 0);
1610    if (!file->index.file) { goto err_index;}
1611    file->index.file->size = file->cfg.index.soft;
1612
1613    /* Do not set O_DIRECT flag for index */
1614    file->rd_index = bpvrfifo_read_open(indexname, false, file->index.file, NULL, 0);
1615    if (!file->rd_index) { goto err_rd_index;}
1616
1617    file->self.index = bpvrfifo_write_file(file->index.file);
1618    file->self.data = bpvrfifo_write_file(file->data.file);
1619
1620    file->self.close = bfile_fifo_close_out;
1621
1622    file->index_entrysize = BNAV_GetEntrySize(BNAV_VersionOriginal); /* default */
1623    file->bcm_player = NULL;
1624
1625    file->index.trim_count = file->data.trim_count = 0;
1626    file->index.trim_off = file->data.trim_off = 0;
1627
1628    /* timer shall be the last call in the initialization sequence */
1629    file->timer = NEXUS_ScheduleTimer(B_TRIM_TIMER, b_trim_timer, file);  /* schedulle heartbeat for the trim */
1630    if (!file->timer) { goto err_timer; }
1631
1632    return file;
1633
1634err_timer:
1635    bpvrfifo_read_close(file->rd_index);
1636err_rd_index:
1637    bpvrfifo_write_close(file->index.file);
1638err_index:
1639    bpvrfifo_write_close(file->data.file);
1640err_data:
1641    BKNI_Free(file);
1642err_alloc:
1643    return NULL;
1644}
1645
1646NEXUS_Error
1647bfile_io_write_set(struct bfile_io_write_fifo *file, const NEXUS_ChunkedFifoRecordLimit *cfg, const char *template)
1648{
1649    BDBG_ASSERT(file);
1650    BDBG_ASSERT(cfg);
1651
1652    if(file->header->active && (file->header->chunked != (cfg->chunkSize!=0))) {
1653        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1654    }
1655    for(;;) {
1656        b_lock(file);
1657        if(file->header->busy==0) {
1658            break;
1659        }
1660        b_unlock(file);
1661        BDBG_WRN(("bfile_io_write_fifo: %#lx collision in access to the file", (unsigned long)file));
1662        BKNI_Sleep(1);
1663    }
1664
1665    file->header->data.h.type = cfg->chunkSize != 0 ? bpvrfifo_type_master : bpvrfifo_type_unit;
1666    if(!file->header->chunked && cfg->chunkSize != 0) {
1667        B_ENTRY(file, 0)->doff = 0; /* data in chunk always starts from 0 */
1668        B_ENTRY(file, 0)->no = file->next_chunk;
1669        b_pvrfifo_register_new_chunk(file);
1670    }
1671
1672    file->header->chunked = cfg->chunkSize != 0;
1673    if(template) {
1674        b_file_strcpy(file->header->data.h.meta.master.chunkTemplate, sizeof(file->header->data.h.meta.master.chunkTemplate), template);
1675    }
1676    if(file->header->chunked) {
1677        file->size = cfg->chunkSize;
1678    } else {
1679        file->size = cfg->soft;
1680    }
1681    b_unlock(file);
1682    return NEXUS_SUCCESS;
1683}
1684
1685
1686NEXUS_FileRecordHandle
1687NEXUS_ChunkedFifoRecord_GetFile(NEXUS_ChunkedFifoRecordHandle file)
1688{
1689    return &file->self;
1690}
1691
1692NEXUS_Error
1693NEXUS_ChunkedFifoRecord_GetPosition(NEXUS_ChunkedFifoRecordHandle file, NEXUS_FilePosition *first, NEXUS_FilePosition *last)
1694{
1695    long firstIndex, lastIndex;
1696    BNAV_Player_Position pos;
1697    int rc;
1698
1699    b_trim_try_player(file);
1700    if(file->bcm_player==NULL) {
1701        BDBG_MSG(("index file is empty, position can't be extracted"));
1702        /* fill them with zeros */
1703        if(first) {
1704            first->mpegFileOffset = 0;
1705            first->indexOffset = NEXUS_FILE_INVALID_POSITION;
1706            first->timestamp = NEXUS_FILE_INVALID_POSITION;
1707        }
1708        if(last) { /* fill them with zeros */
1709            last->mpegFileOffset = 0;
1710            last->indexOffset = NEXUS_FILE_INVALID_POSITION;
1711            last->timestamp = NEXUS_FILE_INVALID_POSITION;
1712        }
1713        return NEXUS_SUCCESS;
1714    }
1715    rc = bp_bounds(file->bcm_player, file, &firstIndex, &lastIndex);
1716    if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); }
1717    if (first) {
1718        rc = BNAV_Player_GetPositionInformation(file->bcm_player, firstIndex, &pos);
1719        if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); }
1720        first->indexOffset = pos.index;
1721        first->timestamp = pos.timestamp;
1722        first->mpegFileOffset = B_GET_OFF_T(&pos);
1723    }
1724    if (last) {
1725        rc = BNAV_Player_GetPositionInformation(file->bcm_player, lastIndex, &pos);
1726        if (rc!=0) { return BERR_TRACE(NEXUS_UNKNOWN); }
1727        last->indexOffset = pos.index;
1728        last->timestamp = pos.timestamp;
1729        last->mpegFileOffset = B_GET_OFF_T(&pos);
1730    }
1731    return NEXUS_SUCCESS;
1732}
1733
1734void
1735NEXUS_ChunkedFifoRecord_GetSettings(NEXUS_ChunkedFifoRecordHandle file, NEXUS_ChunkedFifoRecordSettings *settings)
1736{
1737    /* settings are read only, so wa don't need synchronization here */
1738    *settings = file->cfg;
1739    return;
1740}
1741
1742
1743NEXUS_Error
1744NEXUS_ChunkedFifoRecord_SetSettings(NEXUS_ChunkedFifoRecordHandle file, const NEXUS_ChunkedFifoRecordSettings *settings)
1745{
1746    NEXUS_Error rc = NEXUS_SUCCESS;
1747    if (
1748        settings->index.soft <= 2*sizeof(*file->data.file->header) ||
1749        settings->index.soft >= 2*1024*1024*(off_t)1024 ||
1750        settings->index.hard <= 2*sizeof(*file->data.file->header) ||
1751        settings->index.hard >= 2*1024*1024*(off_t)1024 ||
1752        settings->index.hard < settings->index.soft ||
1753        settings->data.soft <= B_DATA_ALIGN ||
1754        settings->data.hard <= B_DATA_ALIGN ||
1755        settings->data.hard < settings->index.soft )
1756    {
1757        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1758    }
1759    /* we don't need synchronization here either */
1760    file->cfg = *settings;
1761    file->cfg.data.chunkSize -= file->cfg.data.chunkSize % B_DATA_ALIGN;
1762    file->cfg.data.soft -= file->cfg.data.soft % B_DATA_ALIGN;
1763    file->cfg.data.hard -= file->cfg.data.hard % B_DATA_ALIGN;
1764    BDBG_INSTANCE_MSG(file, ("fifo_out_set: %u index(%lld:%lld) data(%lld:%lld)", file->cfg.interval, file->cfg.data.soft, file->cfg.data.hard, file->cfg.index.soft, file->cfg.index.hard));
1765    /* XXX we should truncate file somewhere, sometime */
1766    b_lock(file->index.file);
1767    file->index.file->size = file->cfg.index.soft;
1768    b_unlock(file->index.file);
1769    b_lock(file->data.file);
1770    file->data.file->size = file->cfg.data.soft;
1771    b_unlock(file->data.file);
1772
1773    rc = bfile_io_write_set(file->index.file, &settings->index, settings->chunkTemplate);
1774    if(rc!=NEXUS_SUCCESS) {
1775        goto err_index;
1776    }
1777
1778    rc = bfile_io_write_set(file->data.file, &settings->data, settings->chunkTemplate);
1779    if(rc!=NEXUS_SUCCESS) {
1780        goto err_data;
1781    }
1782
1783    return NEXUS_SUCCESS;
1784err_data:
1785err_index:
1786    return rc;
1787}
1788
Note: See TracBrowser for help on using the repository browser.