intgen_t stobj_get_sessinfo ( inv_sestoken_t tok, invt_seshdr_t *hdr, invt_session_t *ses ) { int rval; int fd = tok->sd_invtok->d_stobj_fd; /* get the session header first */ if ( ( rval = GET_REC_NOLOCK( fd, hdr, sizeof( invt_seshdr_t ), tok->sd_sesshdr_off ) ) > 0 ) { rval = GET_REC_NOLOCK( fd, ses, sizeof( invt_session_t ), tok->sd_session_off ); } return rval; }
intgen_t get_counters( int fd, void **cntpp, size_t cntsz ) { /* object must be locked at least SHARED by caller */ u_int num; ASSERT( cntsz >= sizeof( invt_counter_t ) ); *cntpp = calloc( 1, cntsz); /* find the number of sessions and the max possible */ if ( GET_REC_NOLOCK( fd, (void *) *cntpp, cntsz, (off64_t) 0 ) < 0 ) { free( *cntpp ); *cntpp = NULL; return -1; } num = ((invt_counter_t *)(*cntpp))->ic_curnum; if ( ( (invt_counter_t *)(*cntpp))->ic_vernum != INV_VERSION ) { mlog( MLOG_NORMAL | MLOG_INV, "INV : Unknown version %d - Expected version %d \n", (int) ( (invt_counter_t *)(*cntpp))->ic_vernum, (int) INV_VERSION ); ASSERT ( ((invt_counter_t *)(*cntpp))->ic_vernum == INV_VERSION ); } return (intgen_t) num; }
bool_t stobj_getsession_bylabel( int fd, invt_seshdr_t *hdr, void *seslabel, void **buf ) { invt_session_t ses; /* retrieve the session */ if ( GET_REC_NOLOCK( fd, &ses, sizeof( invt_session_t ), hdr->sh_sess_off ) < 0 ) return -1; /* now see if this is the one that caller is askin for */ if (! STREQL(ses.s_label, (char *)seslabel)) { return BOOL_FALSE; } /* yay. we found the session. so, make the session struct and put it in the buffer */ stobj_copy_invsess(fd, hdr, &ses, (inv_session_t **)buf); return BOOL_TRUE; }
intgen_t stobj_make_invsess( int fd, inv_session_t **buf, invt_seshdr_t *hdr ) { invt_session_t ses; /* load in the rest of the session, but not the streams */ if ( GET_REC_NOLOCK( fd, &ses, sizeof(ses), hdr->sh_sess_off ) < 0 ) { return -1; } return stobj_copy_invsess(fd, hdr, &ses, buf); }
intgen_t get_headers( int fd, void **hdrs, size_t bufsz, size_t off ) { *hdrs = malloc( bufsz ); if ( *hdrs == NULL ) { INV_PERROR( "get_headers() - malloc(seshdrs)\n" ); return -1; } /* file must be locked at least SHARED by caller */ /* get the array of hdrs */ if ( GET_REC_NOLOCK( fd, (void *) *hdrs, bufsz, (off64_t)off ) < 0 ) { free ( *hdrs ); *hdrs = NULL; return -1; } return 1; }
intgen_t stobj_sortheaders( int fd, u_int num ) { size_t sz = sizeof( invt_seshdr_t ) * num; invt_seshdr_t *hdrs; #ifdef INVT_DEBUG int i; #endif if ( num < 2 ) return 1; hdrs = malloc( sz ); ASSERT( hdrs ); if ( GET_REC_NOLOCK( fd, hdrs, sz, STOBJ_OFFSET( 0, 0 ) ) < 0 ) { free ( hdrs ); return -1; } #ifdef INVT_DEBUG printf("\nBEF\n" ); for (i=0; i<(int)num; i++) printf("%ld\n", (long) hdrs[i].sh_time ); #endif qsort( (void*) hdrs, (size_t) num, sizeof( invt_seshdr_t ), stobj_hdrcmp ); #ifdef INVT_DEBUG printf("\n\nAFT\n" ); for (i=0; i<(int)num; i++) printf("%ld\n", (long) hdrs[i].sh_time ); #endif if ( PUT_REC_NOLOCK( fd, hdrs, sz, STOBJ_OFFSET( 0, 0 ) ) < 0 ) { free ( hdrs ); return -1; } free ( hdrs ); return 1; }
/* ARGSUSED */ bool_t stobj_delete_mobj(int fd, invt_seshdr_t *hdr, void *arg , void **buf ) { /* XXX fd needs to be locked EX, not SH */ uuid_t *moid = *buf; invt_session_t ses; invt_stream_t *strms; off64_t off; invt_mediafile_t *mf, *mfiles; u_int nmfiles; u_int i, j; bool_t dirty; if ( GET_REC_NOLOCK( fd, &ses, sizeof( invt_session_t ), hdr->sh_sess_off ) < 0 ) return -1; /* now get all the streams of this session */ strms = calloc ( ses.s_cur_nstreams, sizeof( invt_stream_t ) ); if ( GET_REC_NOLOCK( fd, strms, sizeof( invt_stream_t ) * ses.s_cur_nstreams, hdr->sh_streams_off ) < 0 ) { free ( strms ); return BOOL_FALSE; } /* now look at all the mediafiles in all the streams */ for ( i = 0; i < ses.s_cur_nstreams; i++ ) { off = strms[i].st_firstmfile; nmfiles = strms[i].st_nmediafiles; mfiles = mf = calloc( nmfiles, sizeof( invt_mediafile_t ) ); for ( j = 0; j < nmfiles; j++, off = mf->mf_nextmf, mf++ ) { /* The prob is that we need to keep track of where we got these mfiles from as we get them, or we wont know how to put them back if they are dirty. */ ASSERT( off ); if ( GET_REC_NOLOCK( fd, mf, sizeof( invt_mediafile_t ), off ) <= 0 ) { free( strms ); free( mfiles ); return BOOL_FALSE; } } /* We have all the media files of this stream. Make another pass, checking to see if we need to remove any mfiles */ dirty = BOOL_FALSE; for ( j = 0; j < nmfiles; j++ ) { mf = &mfiles[j]; if ( !uuid_compare( mf->mf_moid, *moid ) ) { #ifdef INVT_DEBUG printf(" found one\n" ); #endif /* dirty = BOOL_TRUE; if ( j == 0 ) strms[i].st_firstmfile = mf->mf_nextmf; else mfiles[j-1].mf_nextmf = mf->mf_nextmf; if ( j == nmfiles - 1 ) strms[i].st_lastmfile = ; */ } } free ( mfiles ); if ( dirty ); } free ( strms ); return BOOL_FALSE; /* ret FALSE, or it'll stop iteration */ }
bool_t stobj_pack_sessinfo( int fd, invt_session_t *ses, invt_seshdr_t *hdr, void **bufpp, size_t *bufszp ) { size_t stmsz; u_int i, j; size_t sessz; invt_stream_t *strms; char *sesbuf, *sesbufcp; off64_t off; invt_mediafile_t mf; stmsz = sizeof( invt_stream_t ) * ses->s_cur_nstreams; /* the initial size without the mediafiles */ sessz = strlen( INVTSESS_COOKIE ) * sizeof( char ) + sizeof( inv_version_t ) + sizeof( inv_version_t ) + /* added to fix 64 bit alignment prob */ sizeof( invt_session_t) + sizeof( invt_seshdr_t ) + stmsz; /* now get all the streams of this session */ strms = calloc ( ses->s_cur_nstreams, sizeof( invt_stream_t ) ); if ( GET_REC_NOLOCK( fd, strms, stmsz, hdr->sh_streams_off ) < 0 ) { free ( strms ); return BOOL_FALSE; } for ( i = 0; i < ses->s_cur_nstreams; i++ ) sessz += sizeof( invt_mediafile_t ) * (size_t) strms[i].st_nmediafiles; /* Now we know how big this entire thing is going to be */ sesbufcp = sesbuf = calloc( 1, sessz ); ASSERT( sesbuf ); /* Copy everything. Note that we don't bother to adjust the offsets either in the seshdr or in the mediafiles, because we don't need those in order to restore this session ( since everything's contiguous ) */ /* magic cookie that we put for sanity checking in case of an earthquake or something :) */ strcpy( sesbuf, INVTSESS_COOKIE ); sesbuf += (size_t)( strlen( INVTSESS_COOKIE ) * sizeof( char ) ); /* This was originally INV_VERSION. Changed it to mean packed inventory * version number and added another inv_version_t to contain the INV_VERSION. * The primary intent of this change was to make everything 64 bit aligned, * but we also got the advantage of separating the packed inv version from * the general inventory version */ *(inv_version_t *)sesbuf = INT_GET(PACKED_INV_VERSION, ARCH_CONVERT); sesbuf += sizeof( inv_version_t ); /* This has the INV_VERSION */ *(inv_version_t *)sesbuf = INT_GET(INV_VERSION, ARCH_CONVERT); sesbuf += sizeof( inv_version_t ); xlate_invt_seshdr(hdr, (invt_seshdr_t *)sesbuf, 1); sesbuf += sizeof( invt_seshdr_t ); xlate_invt_session( ses, (invt_session_t *)sesbuf, 1 ); sesbuf += sizeof( invt_session_t ); for ( i = 0; i < ses->s_cur_nstreams; i++ ) { xlate_invt_stream( strms, (invt_stream_t *)sesbuf, 1 ); sesbuf += sizeof( invt_stream_t ); } /* now append all the mediafiles */ for ( i = 0; i < ses->s_cur_nstreams; i++ ) { off = strms[i].st_firstmfile; for ( j = 0; j < strms[i].st_nmediafiles; j++, off = mf.mf_nextmf ) { ASSERT( off ); if ( GET_REC_NOLOCK( fd, &mf, sizeof( invt_mediafile_t ), off ) <= 0 ) { free( strms ); free( sesbuf ); return BOOL_FALSE; } xlate_invt_mediafile(&mf, (invt_mediafile_t *)sesbuf, 1); sesbuf += sizeof( invt_mediafile_t ); } } free( strms ); *bufpp = sesbufcp; *bufszp = sessz; return BOOL_TRUE; }
intgen_t stobj_put_mediafile( inv_stmtoken_t tok, invt_mediafile_t *mf ) { int rval; invt_sescounter_t *sescnt = NULL; invt_stream_t stream; inv_sestoken_t sestok = tok->md_sesstok; int fd = sestok->sd_invtok->d_stobj_fd; off64_t pos; /* first we need to find out where the current write-position is. so, we first read the sescounter that is at the top of this storage object */ if ( GET_SESCOUNTERS( fd, &sescnt ) < 0 ) return -1; pos = sescnt->ic_eof; /* increment the pointer to give space for this media file */ sescnt->ic_eof += (off64_t) sizeof( invt_mediafile_t ); if ( PUT_SESCOUNTERS( fd, sescnt ) < 0 ) return -1; /* get the stream information, and update number of mediafiles. we also need to link the new mediafile into the linked-list of media files of this stream */ if ( GET_REC_NOLOCK( fd, &stream, sizeof( stream ), tok->md_stream_off ) < 0 ) return -1; /* We need to update the last ino of this STREAM, which is now the last ino of the new mediafile. If this is the first mediafile, we have to update the startino as well. Note that ino is a <ino,off> tuple */ if ( ! ( mf->mf_flag & INVT_MFILE_INVDUMP )) { if ( stream.st_nmediafiles == 0 ) stream.st_startino = mf->mf_startino; stream.st_endino = mf->mf_endino; } stream.st_nmediafiles++; #ifdef INVT_DEBUG mlog (MLOG_VERBOSE, "#################### mediafile #%d " "###################\n", stream.st_nmediafiles); #endif /* add the new mediafile at the tail of the list */ mf->mf_nextmf = tok->md_stream_off; mf->mf_prevmf = stream.st_lastmfile; if ( tok->md_lastmfile ) tok->md_lastmfile->mf_nextmf = pos; else { stream.st_firstmfile = pos; } stream.st_lastmfile = pos; /* write the stream to disk */ if ( PUT_REC_NOLOCK( fd, &stream, sizeof( stream ), tok->md_stream_off ) < 0 ) return -1; /* write the prev media file to disk too */ if ( tok->md_lastmfile ) { rval = PUT_REC_NOLOCK( fd, tok->md_lastmfile, sizeof( invt_mediafile_t ), mf->mf_prevmf ); free ( tok->md_lastmfile ); if ( rval < 0 ) return -1; } if ( ! ( mf->mf_flag & INVT_MFILE_INVDUMP )) { tok->md_lastmfile = mf; } else { tok->md_lastmfile = NULL; } /* at last, write the new media file to disk */ rval = PUT_REC_NOLOCK( fd, mf, sizeof( invt_mediafile_t ), pos ); if ( rval < 0 ) { return -1; } return rval; }
/*----------------------------------------------------------------------*/ intgen_t stobj_insert_session( invt_idxinfo_t *idx, int fd, /* kept locked EX by caller */ invt_sessinfo_t *s ) { invt_sescounter_t *sescnt = NULL; if ( GET_SESCOUNTERS( fd, &sescnt ) < 0 ) { INVLOCK( fd, LOCK_UN ); return -1; } /* Check the existing sessions to make sure that we're not duplicating this session */ if ( sescnt->ic_curnum > 0 ) { u_int i; invt_session_t *sessions = calloc( sescnt->ic_curnum, sizeof( invt_session_t ) ); if ( GET_REC_NOLOCK( fd, sessions, sescnt->ic_curnum * sizeof( invt_session_t ), (off64_t) ( sizeof( *sescnt ) + sescnt->ic_maxnum * sizeof( invt_seshdr_t ))) < 0 ) { free ( sescnt ); free ( sessions ); return -1; } for( i = 0; i < sescnt->ic_curnum; i++ ) { if ( uuid_compare( sessions[i].s_sesid, s->ses->s_sesid ) == 0 ) break; } free ( sessions ); if ( i < sescnt->ic_curnum ) { mlog( MLOG_DEBUG | MLOG_INV, "INV: attempt to insert an " "existing session.\n" ); free ( sescnt ); return 1; } } if ( sescnt->ic_curnum >= sescnt->ic_maxnum ) { if ( stobj_split( idx, fd, sescnt, s ) < 0 ) { free( sescnt ); return -1; } free( sescnt ); return 1; } if ( stobj_put_session( fd, sescnt, s->ses, s->seshdr, s->strms, s->mfiles ) < 0 ){ free ( sescnt); return -1; } free ( sescnt); return 1; }
intgen_t stobj_split( invt_idxinfo_t *idx, int fd, invt_sescounter_t *sescnt, invt_sessinfo_t *newsess ) { invt_seshdr_t *harr = NULL; u_int i, ix, ns = sescnt->ic_curnum; void *bufpp; size_t bufszp; invt_sessinfo_t sesinfo; invt_entry_t ient; if ( GET_SESHEADERS( fd, &harr, ns ) < 0 ) return -1; ASSERT( harr != NULL ); if ( ( ix = stobj_find_splitpoint( fd, harr, ns, newsess->seshdr->sh_time ) ) == 0 ) return -1; if ( ix == ns ) { ient.ie_timeperiod.tp_start = ient.ie_timeperiod.tp_end = newsess->seshdr->sh_time; } else { ient.ie_timeperiod.tp_start = ient.ie_timeperiod.tp_end = harr[ix].sh_time; if ( harr[ix - 1].sh_time > newsess->seshdr->sh_time ) idx->iarr[idx->index].ie_timeperiod.tp_end = harr[ix - 1].sh_time; else idx->iarr[idx->index].ie_timeperiod.tp_end = newsess->seshdr->sh_time; } /* Get the new stobj to put the 'spilling' sessinfo in. We know the idx of the current stobj, and by definition, the new stobj should come right afterwards. */ newsess->stobjfd = idx_put_newentry( idx, &ient ); if ( newsess->stobjfd < 0 ) return -1; if ( ix == ns ) { invt_sescounter_t *scnt = NULL; off64_t rval; /* We dont need to split. So, just put the new session in the new stobj, and rest in peace */ idx->index++; if ( GET_SESCOUNTERS( newsess->stobjfd, &scnt ) < 0 ) return -1; rval = stobj_put_session( newsess->stobjfd, scnt, newsess->ses, newsess->seshdr, newsess->strms, newsess->mfiles ); free( scnt ); return (rval < 0)? -1: 1; } for ( i = ix; i < ns; i++ ) { invt_session_t session; bufpp = NULL; bufszp = 0; newsess->seshdr->sh_sess_off = harr[i].sh_sess_off; if ( GET_REC_NOLOCK( fd, &session, sizeof( invt_session_t ), harr[i].sh_sess_off ) < 0 ) return -1; if (! stobj_pack_sessinfo( fd, &session, &harr[i], &bufpp, &bufszp )) return -1; /* Now we need to put this in the new StObj. So, first unpack it. */ if (! stobj_unpack_sessinfo( bufpp, bufszp, &sesinfo ) ) return -1; /* There is no chance of a recursion here */ if ( stobj_insert_session( idx, newsess->stobjfd, &sesinfo ) < 0 ) return -1; /* Now delete that session from this StObj */ if (! stobj_delete_sessinfo( fd, sescnt, &session, &harr[i] ) ) return -1; free( bufpp ); } /* Put the new session in the stobj that we just split. Make sure that we use the updated sescnt and not the stale stuff from disk. stobj_put_session() writes sescnt and sessinfo to disk */ if ( stobj_put_session( fd, sescnt, newsess->ses, newsess->seshdr, newsess->strms, newsess->mfiles ) < 0 ) { free ( sescnt); return -1; } return 1; }
intgen_t stobj_copy_invsess(int fd, invt_seshdr_t *hdr, invt_session_t *ses, inv_session_t **buf) { inv_session_t *ises; invt_stream_t *strms; int i; invt_mediafile_t mf; strms = calloc ( ses->s_cur_nstreams, sizeof( invt_stream_t ) ); /* load in all the stream-headers */ if ( GET_REC_NOLOCK( fd, strms, ses->s_cur_nstreams * sizeof( invt_stream_t ), hdr->sh_streams_off ) < 0 ) { free (strms); return -1; } ises = calloc( 1, sizeof( inv_session_t ) ); stobj_convert_session(ises, ses, hdr); ises->s_streams = calloc(ses->s_cur_nstreams, sizeof( inv_stream_t )); /* fill in the stream structures too */ i = (int) ses->s_cur_nstreams; while ( i-- ) { off64_t off; u_int j, nmf; stobj_convert_strm(&ises->s_streams[i], &strms[i]); nmf = strms[i].st_nmediafiles; off = strms[i].st_firstmfile; if (nmf) ises->s_streams[i].st_mediafiles = calloc( nmf, sizeof( inv_mediafile_t ) ); ASSERT( !nmf || ises->s_streams[i].st_mediafiles ); for ( j = 0; j < nmf; j++, off = mf.mf_nextmf ) { ASSERT( off ); if ( GET_REC_NOLOCK( fd, &mf, sizeof( invt_mediafile_t ), off ) <= 0 ) { INV_PERROR( "stobj::make_invsess\n" ); free( strms ); free( ises ); return -1; } /* copy the mediafile into the exported structure */ if (ises->s_streams[i].st_mediafiles) { stobj_convert_mfile( &ises->s_streams[i].st_mediafiles[j], &mf); } else { mlog(MLOG_ERROR, _( "Failed to get data from media file: " "possible file corruption\n") ); mlog_exit_hint(RV_CORRUPT); return -1; } } } free( strms ); *buf = ises; return 1; }