| /* |
| * Copyright (c) 2000-2001 Silicon Graphics, Inc. |
| * All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include <xfs/xfs.h> |
| #include <xfs/jdm.h> |
| |
| #include <time.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <sys/file.h> |
| #include <sys/stat.h> |
| #include <sys/dir.h> |
| #include "types.h" |
| #include "mlog.h" |
| #include "inv_priv.h" |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* insert_invindexentry */ |
| /* */ |
| /* given a time, find the invindex that has the time-period it can fit */ |
| /* into. */ |
| /*----------------------------------------------------------------------*/ |
| u_int |
| idx_insert_newentry( int fd, /* kept locked EX by caller */ |
| int *stobjfd, /* OUT */ |
| invt_entry_t *iarr, invt_counter_t *icnt, |
| time32_t tm ) |
| { |
| u_int i; |
| inv_oflag_t forwhat = INV_SEARCH_N_MOD; |
| /* invt_entry_t ient; |
| ient.ie_timeperiod.tp_start = ient.ie_timeperiod.tp_end = tm; */ |
| |
| /* If time period of the new entry is before our first invindex, |
| we have to insert a new invindex in the first slot */ |
| if ( iarr[0].ie_timeperiod.tp_start > tm ) { |
| /* *stobjfd = idx_put_newentry( fd, 0, iarr, icnt, &ient );*/ |
| *stobjfd = open( iarr[0].ie_filename, INV_OFLAG(forwhat) ); |
| return 0; |
| } |
| |
| for ( i = 0; i < icnt->ic_curnum; i++ ) { |
| /* if our time is nicely within an existing entry's time |
| period, hellalujah */ |
| if ( IS_WITHIN( &iarr[i].ie_timeperiod, tm ) ) { |
| #ifdef INVT_DEBUG |
| mlog( MLOG_DEBUG | MLOG_INV, "INV: is_within %d\n",i ); |
| #endif |
| *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); |
| return i; |
| } |
| if ( iarr[i].ie_timeperiod.tp_end == 0 && |
| iarr[i].ie_timeperiod.tp_start == 0 ) { |
| #ifdef INVT_DEBUG |
| mlog( MLOG_DEBUG | MLOG_INV, "INV: end = start \n" ); |
| mlog( MLOG_DEBUG | MLOG_INV,"BEF: st %ld end %ld\n", |
| iarr[i].ie_timeperiod.tp_start, |
| iarr[i].ie_timeperiod.tp_end ); |
| #endif |
| |
| iarr[i].ie_timeperiod.tp_start = |
| iarr[i].ie_timeperiod.tp_end = tm; |
| PUT_REC_NOLOCK( fd, iarr, |
| icnt->ic_curnum * sizeof(invt_entry_t), |
| (off64_t) sizeof( invt_counter_t ) ); |
| #ifdef INVT_DEBUG |
| mlog( MLOG_DEBUG | MLOG_INV,"AFT: st %ld end %ld\n", |
| iarr[i].ie_timeperiod.tp_start, |
| iarr[i].ie_timeperiod.tp_end ); |
| #endif |
| *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); |
| return i; |
| } |
| |
| |
| |
| /* if it is beyond the end of this timeperiod, see if we |
| belong to a timeperiod that doesn't have an entry */ |
| if ( iarr[i].ie_timeperiod.tp_end < tm ) { |
| /* see if we're the last entry here */ |
| if ( i == icnt->ic_curnum - 1 ) { |
| /* our slot is (i+1)th entry. Make the |
| timeperiod's the same as it was. As far |
| as I can see there is no way that |
| timeperiods can overlap. |
| |
| insert the new entry and write back |
| icnt and invindex entry */ |
| /* *stobjfd = idx_put_newentry( fd, i+1, iarr, |
| icnt, &ient );*/ |
| *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); |
| return i; |
| } |
| /* see if the next entry starts later than us */ |
| if ( iarr[i+1].ie_timeperiod.tp_start > tm ) { |
| |
| |
| /* We have the option of pushing entries |
| after (i) forward by one slot, and |
| taking the (i+1)th slot, OR just hooking |
| up with the next entry. |
| We choose the former. */ |
| |
| /* the timeperiods had better not overlap */ |
| ASSERT(( tm > iarr[i].ie_timeperiod.tp_end ) && |
| ( tm < iarr[i+1].ie_timeperiod.tp_start )); |
| |
| /* shift everything from (i+1) onwards by |
| one. Then insert the new entry and write |
| back icnt and invindex entries */ |
| /* *stobjfd = idx_put_newentry( fd, i+1, iarr, |
| icnt, &ient );*/ |
| *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); |
| return i; |
| } |
| } |
| } |
| |
| /* We couldnt find anything that fits */ |
| ASSERT( 0 ); /* We can't get here ! */ |
| return -1; |
| |
| |
| } |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* idx_put_newentry */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| intgen_t |
| idx_put_newentry( |
| invt_idxinfo_t *idx, |
| invt_entry_t *ient ) |
| { |
| invt_entry_t *idxarr; |
| int stobjfd; |
| |
| int fd = idx->invfd; /* kept locked EX by caller */ |
| u_int index = idx->index + 1; |
| invt_entry_t *iarr = idx->iarr; |
| invt_counter_t *icnt = idx->icnt; |
| |
| stobj_makefname( ient->ie_filename ); |
| if ( ( stobjfd = stobj_create( ient->ie_filename ) ) < 0 ) |
| return -1; |
| |
| icnt->ic_curnum++; /* there is no maximum */ |
| |
| idxarr = ( invt_entry_t * ) calloc ( icnt->ic_curnum, |
| sizeof( invt_entry_t ) ); |
| memcpy( idxarr, iarr, ( size_t ) ( sizeof( invt_entry_t ) * index ) ); |
| |
| /* shift everything from (i+1) onwards by one */ |
| if ( index < icnt->ic_curnum - 1 ) |
| memcpy( &idxarr[ index + 1 ], &iarr[ index ], |
| ( size_t ) ( ( icnt->ic_curnum - index - 1 ) * |
| sizeof( invt_entry_t ) ) ); |
| /* insert the new entry */ |
| memcpy( &idxarr[ index ], ient, sizeof( invt_entry_t ) ); |
| |
| |
| if ( ( PUT_COUNTERS( fd, icnt ) < 0 ) || |
| ( PUT_REC_NOLOCK( fd, idxarr, |
| icnt->ic_curnum * sizeof( invt_entry_t ), |
| sizeof( invt_counter_t ) ) < 0 ) ) { |
| /* XXX delete the stobj that we just created */ |
| |
| memset( ient->ie_filename, 0 , INV_STRLEN ); |
| free( idxarr ); |
| return -1; |
| } |
| |
| free( iarr ); |
| idx->iarr = idxarr; |
| return stobjfd; |
| |
| } |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* idx_find_stobj */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| |
| int |
| idx_find_stobj( invt_idxinfo_t *idx, |
| time32_t tm ) |
| { |
| |
| int stobjfd; |
| |
| /* since sessions can be inserted in random order, the invindex |
| table can contain time-periods that don't have corresponding |
| entries for */ |
| if ( GET_ALLHDRS_N_CNTS_NOLOCK( idx->invfd, (void **)&idx->iarr, |
| (void **)&idx->icnt, |
| sizeof( invt_entry_t ), |
| sizeof( invt_counter_t ) ) < 0 ) { |
| return -1; |
| } |
| |
| #ifdef INVT_DEBUG |
| printf( "idx_find_stobj Time: %ld\n", tm ); |
| idx_DEBUG_printinvindices( idx->iarr, idx->icnt->ic_curnum ); |
| #endif |
| |
| /* Now figure out where we are going to insert this stobj among the |
| invindices and put it there */ |
| idx->index = idx_insert_newentry( idx->invfd, &stobjfd, idx->iarr, |
| idx->icnt, tm ); |
| |
| return stobjfd; |
| } |
| |
| |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| inv_idbtoken_t |
| idx_create( char *fname, inv_oflag_t forwhat ) |
| { |
| int stobjfd, fd; |
| inv_idbtoken_t tok; |
| |
| /* This is not to be called when the user wants to open |
| the db for SEARCH_ONLY. */ |
| ASSERT( forwhat != INV_SEARCH_ONLY ); |
| |
| if ((fd = open ( fname , INV_OFLAG(forwhat) | O_CREAT, S_IRUSR|S_IWUSR ) ) < 0 ) { |
| INV_PERROR ( fname ); |
| return INV_TOKEN_NULL; |
| } |
| |
| INVLOCK( fd, LOCK_EX ); |
| fchmod( fd, INV_PERMS ); |
| |
| #ifdef INVT_DEBUG |
| mlog( MLOG_NITTY | MLOG_INV, "creating InvIndex %s\n", fname); |
| #endif |
| |
| /* create the first entry in the new inv_index */ |
| stobjfd = idx_create_entry( &tok, fd, BOOL_TRUE ); |
| |
| INVLOCK( fd, LOCK_UN ); |
| |
| if ( stobjfd < 0 ) |
| return INV_TOKEN_NULL; |
| return tok; |
| } |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* idx_recons_time */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| intgen_t |
| idx_recons_time( time32_t tm, invt_idxinfo_t *idx ) |
| { |
| invt_timeperiod_t *tp = &idx->iarr[idx->index].ie_timeperiod; |
| if ( tp->tp_start && IS_WITHIN( tp, tm ) ) |
| return 1; |
| |
| if ( tm > tp->tp_end || tp->tp_end == 0 ) |
| tp->tp_end = tm; |
| if ( tm < tp->tp_start || tp->tp_start == 0 ) |
| tp->tp_start = tm; |
| PUT_REC_NOLOCK( idx->invfd, &idx->iarr[idx->index], |
| sizeof( invt_entry_t ), IDX_HDR_OFFSET(idx->index) ); |
| return 1; |
| } |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* put_sesstime */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| intgen_t |
| idx_put_sesstime( inv_sestoken_t tok, bool_t whichtime) |
| { |
| int rval; |
| invt_entry_t ent; |
| int fd = tok->sd_invtok->d_invindex_fd; |
| |
| INVLOCK( fd, LOCK_EX ); |
| |
| rval = GET_REC_NOLOCK( fd, &ent, sizeof( invt_entry_t ), |
| tok->sd_invtok->d_invindex_off); |
| if ( rval < 0 ) { |
| INVLOCK( fd, LOCK_UN ); |
| return -1; |
| } |
| ent.ie_timeperiod.tp_end = tok->sd_sesstime; |
| |
| if ( whichtime == INVT_STARTTIME || ent.ie_timeperiod.tp_start == 0 ) { |
| ent.ie_timeperiod.tp_start = tok->sd_sesstime; |
| } |
| #ifdef INVT_DEBUG |
| mlog( MLOG_DEBUG | MLOG_INV,"Putsestime: st %ld end %ld\n", |
| ent.ie_timeperiod.tp_start, |
| ent.ie_timeperiod.tp_end ); |
| #endif |
| rval = PUT_REC_NOLOCK_SEEKCUR( fd, &ent, sizeof( invt_entry_t ), |
| -(off64_t)(sizeof( invt_entry_t ))); |
| |
| #ifdef INVT_DEBUG |
| { |
| int nindices; |
| invt_entry_t *iarr = NULL; |
| invt_counter_t *icnt = NULL; |
| if ( ( nindices = GET_ALLHDRS_N_CNTS_NOLOCK( fd, |
| (void **)&iarr, |
| (void **)&icnt, |
| sizeof( invt_entry_t ), |
| sizeof( invt_counter_t ))) < 0 ) { |
| return -1; |
| } |
| idx_DEBUG_printinvindices( iarr, (u_int) nindices ); |
| free( iarr ); |
| free( icnt ); |
| } |
| #endif |
| |
| INVLOCK( fd, LOCK_UN ); |
| return rval; |
| } |
| |
| |
| |
| /* an inventory index entry keeps track of a single storage object; |
| it knows about its name (ie filename) and the timeperiod that the |
| it contains dump sessions for. |
| note that each file system has its own (set of) inventory indices. |
| */ |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| intgen_t |
| idx_create_entry( |
| inv_idbtoken_t *tok, |
| int invfd, /* kept locked EX by caller */ |
| bool_t firstentry ) |
| { |
| invt_entry_t ent; |
| int fd; |
| off64_t hoff; |
| |
| |
| memset ( &ent, 0, sizeof( ent ) ); |
| |
| /* initialize the start and end times to be the same */ |
| ent.ie_timeperiod.tp_start = ent.ie_timeperiod.tp_end = (time32_t)0; |
| stobj_makefname( ent.ie_filename ); |
| |
| if ( firstentry ) { |
| invt_counter_t cnt; |
| |
| cnt.ic_maxnum = INVT_MAX_INVINDICES; |
| cnt.ic_curnum = 1; |
| cnt.ic_vernum = INV_VERSION; |
| |
| fd = stobj_create( ent.ie_filename ); |
| if ( fd < 0 ) { |
| return -1; |
| } |
| |
| if ( PUT_REC_NOLOCK( invfd, &cnt, sizeof(cnt), (off64_t)0 ) < 0 ) |
| return -1; |
| |
| hoff = sizeof( invt_counter_t ); |
| |
| if ( PUT_REC_NOLOCK( invfd, &ent, sizeof( ent ), hoff ) < 0) |
| return -1; |
| } else { |
| invt_counter_t *cnt = NULL; |
| |
| if ( GET_COUNTERS( invfd, &cnt ) < 0 ) { |
| return -1; |
| } |
| |
| /* XXX check if there are too many indices. if so, create |
| another and leave a pointer to that in here */ |
| |
| /* create the new storage object */ |
| fd = stobj_create( ent.ie_filename ); |
| if ( fd < 0 ) { |
| return -1; |
| } |
| ++(cnt->ic_curnum); |
| if ( PUT_COUNTERS( invfd, cnt ) < 0 ) { |
| return -1; |
| } |
| |
| /* add the new index entry to the array, at the end */ |
| |
| hoff = IDX_HDR_OFFSET( cnt->ic_curnum - 1 ); |
| free (cnt); |
| #ifdef INVT_DEBUG |
| mlog( MLOG_NITTY | MLOG_INV, "new stobj name %s @ offset %d\n", |
| ent.ie_filename,(int)hoff ); |
| #endif |
| if (PUT_REC_NOLOCK( invfd, &ent, sizeof( ent ), hoff) < 0 ) |
| return -1; |
| |
| } |
| |
| *tok = get_token( invfd, fd ); |
| (*tok)->d_invindex_off = hoff; |
| (*tok)->d_update_flag |= NEW_INVINDEX; |
| (*tok)->d_oflag = INV_SEARCH_N_MOD; |
| return fd; |
| |
| } |
| |
| |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| int |
| idx_get_stobj( int invfd, inv_oflag_t forwhat, int *index ) |
| { |
| invt_entry_t *ent = 0; |
| int fd; |
| |
| /* if there's space anywhere at all, then it must be in the last |
| entry. get_lastheader() does the locking */ |
| |
| if ((*index = get_lastheader( invfd, (void **)&ent, |
| sizeof(invt_entry_t), |
| sizeof(invt_counter_t) ) ) < 0 ) |
| return -1; |
| /* at this point we know that there should be at least one invindex |
| entry present */ |
| ASSERT ( ent != NULL ); |
| ASSERT ( ent->ie_filename ); |
| |
| fd = open( ent->ie_filename, INV_OFLAG(forwhat) ); |
| if ( fd < 0 ) |
| INV_PERROR( ent->ie_filename ); |
| free ( ent ); |
| |
| return fd; |
| } |
| |
| |
| intgen_t |
| idx_DEBUG_printinvindices( invt_entry_t *iarr, u_int num ) |
| { |
| u_int i; |
| u_int k; |
| |
| char s[9]; |
| printf( "\n ==================================\n" |
| " InvIndex\n # StObjs\t%d\n", num ); |
| #define INV_UUID_STR_LEN 36 /* not exported via uuid.h */ |
| for ( i = 0; i < num; i++ ) { |
| k = strlen( iarr[i].ie_filename ); |
| strncpy( s, (char *) iarr[i].ie_filename + k - |
| ( INV_UUID_STR_LEN + strlen(INV_STOBJ_PREFIX)), 8 ); |
| s[8]= 0; |
| printf("%d. %s \t( %d - %d )\n", i, s, |
| iarr[i].ie_timeperiod.tp_start, |
| iarr[i].ie_timeperiod.tp_end ); |
| } |
| #undef INV_UUID_STR_LEN |
| printf( "\n ==================================\n"); |
| return 1; |
| |
| } |
| |
| intgen_t |
| idx_DEBUG_print ( int fd ) |
| { |
| int nindices; |
| invt_entry_t *iarr = NULL; |
| invt_counter_t *icnt = NULL; |
| if ( ( nindices = GET_ALLHDRS_N_CNTS_NOLOCK( fd, |
| (void **)&iarr, |
| (void **)&icnt, |
| sizeof( invt_entry_t ), |
| sizeof( invt_counter_t ))) < 0 ) { |
| return -1; |
| } |
| idx_DEBUG_printinvindices( iarr, (u_int) nindices ); |
| free( iarr ); |
| free( icnt ); |
| |
| return 1; |
| } |
| |
| |
| |
| intgen_t |
| DEBUG_displayallsessions( int fd, invt_seshdr_t *hdr, u_int ref, |
| invt_pr_ctx_t *prctx) |
| { |
| inv_session_t *ses; |
| if ( stobj_make_invsess( fd, &ses, hdr ) < 1 ) |
| return -1; |
| |
| DEBUG_sessionprint( ses, ref, prctx); |
| free( ses->s_streams ); |
| free( ses ); |
| |
| return 0; |
| } |
| |