| /* |
| * 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 <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/file.h> |
| #include <fcntl.h> |
| #include <time.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <sys/stat.h> |
| |
| #include "types.h" |
| #include "inventory_priv.h" |
| |
| int sesslock_fd = -1; |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* inventory_open */ |
| /* */ |
| /* INV_BY_MOUNTPT, INV_BY_UUID or INV_BY_DEVPATH */ |
| /*----------------------------------------------------------------------*/ |
| |
| inv_idbtoken_t |
| inv_open( inv_predicate_t bywhat, void *pred ) |
| { |
| |
| int fd, stobjfd, num; |
| char uuname[ INV_STRLEN ]; |
| inv_idbtoken_t tok = INV_TOKEN_NULL; |
| invt_sescounter_t *sescnt = 0; |
| |
| int index = 0; |
| |
| ASSERT ( pred ); |
| if ((fd = init_idb ( pred, bywhat, uuname, &tok )) < 0 ) |
| return tok; |
| |
| /* XXX also, see if it is too full. if so, make another and leave a |
| reference to the new file in the old one */ |
| |
| stobjfd = get_storageobj( fd, &index ); |
| if ( stobjfd < 0 ) { |
| close( fd ); |
| close( sesslock_fd ); |
| sesslock_fd = -1; |
| return INV_TOKEN_NULL; |
| } |
| |
| ASSERT ( index > 0 ); |
| |
| /* Now we need to make sure that this has enough space */ |
| num = GET_SESCOUNTERS( stobjfd, &sescnt ); |
| if ( num < 0 ) { |
| close( fd ); |
| close( stobjfd ); |
| close( sesslock_fd ); |
| sesslock_fd = -1; |
| return INV_TOKEN_NULL; |
| } |
| /* create another storage object ( and, an inv_index entry for it too ) |
| if we've filled this one up */ |
| if ( (u_int) num >= sescnt->ic_maxnum ) { |
| #ifdef INVT_DEBUG |
| printf("$ creating a new storage obj & index entry. \n" ); |
| #endif |
| close (stobjfd); |
| |
| stobjfd = create_invindex_entry( &tok, fd, uuname, BOOL_FALSE ); |
| free ( sescnt ); |
| if ( stobjfd < 0 ) { |
| close( fd ); |
| close( sesslock_fd ); |
| sesslock_fd = -1; |
| return INV_TOKEN_NULL; |
| } |
| return tok; |
| } |
| |
| free ( sescnt ); |
| tok = get_token( fd, stobjfd ); |
| tok->d_invindex_off = INVINDEX_HDR_OFFSET( index - 1 ); |
| |
| return tok; |
| |
| } |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| |
| bool_t |
| inv_close( inv_idbtoken_t tok ) |
| { |
| close ( tok->d_invindex_fd ); |
| close ( tok->d_stobj_fd ); |
| destroy_token( tok ); |
| close( sesslock_fd ); |
| sesslock_fd = -1; |
| |
| return BOOL_TRUE; |
| } |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* inventory_lasttime_level_lessthan */ |
| /* */ |
| /* Given a token that refers to a file system, and a level, this returns*/ |
| /* the last time when a session of a lesser level was done. */ |
| /* */ |
| /* returns -1 on error. */ |
| /*----------------------------------------------------------------------*/ |
| |
| bool_t |
| inv_lasttime_level_lessthan( |
| inv_idbtoken_t tok, |
| u_char level, |
| time32_t **tm ) |
| { |
| int rval; |
| ASSERT ( tok != INV_TOKEN_NULL ); |
| |
| rval = search_invt( tok, level, (void **) tm, |
| (search_callback_t) tm_level_lessthan ); |
| |
| return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; |
| } |
| |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| bool_t |
| inv_lastsession_level_lessthan( |
| inv_idbtoken_t tok, |
| u_char level, |
| inv_session_t **ses ) |
| { |
| int rval; |
| ASSERT ( tok != INV_TOKEN_NULL ); |
| |
| rval = search_invt( tok, level, (void **) ses, |
| (search_callback_t) lastsess_level_lessthan ); |
| |
| return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; |
| |
| } |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* Return FALSE on an error, TRUE if not. If (*ses) is NULL, then the */ |
| /* search failed. */ |
| /*----------------------------------------------------------------------*/ |
| |
| |
| bool_t |
| inv_lastsession_level_equalto( |
| inv_idbtoken_t tok, |
| u_char level, |
| inv_session_t **ses ) |
| { |
| int rval; |
| ASSERT ( tok != INV_TOKEN_NULL ); |
| rval = search_invt( tok, level, (void **) ses, |
| (search_callback_t) lastsess_level_equalto ); |
| |
| return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| inv_sestoken_t |
| inv_writesession_open( |
| inv_idbtoken_t tok, /* token obtained by inventory_open() */ |
| uuid_t *fsid, |
| uuid_t *sesid, |
| char *label, |
| u_char level, |
| u_int nstreams, |
| time32_t time, |
| char *mntpt, |
| char *devpath ) |
| { |
| invt_session_t *ses; |
| int fd; |
| intgen_t rval; |
| invt_sescounter_t *sescnt = NULL; |
| invt_seshdr_t hdr; |
| inv_sestoken_t sestok; |
| |
| ASSERT ( tok != INV_TOKEN_NULL ); |
| ASSERT ( sesid && fsid && mntpt && devpath ); |
| |
| if ( ! ( tok->d_update_flag & FSTAB_UPDATED ) ) { |
| if ( put_fstab_entry( fsid, mntpt, devpath ) < 0 ) { |
| printf ("put_fstab_entry :(\n"); |
| return INV_TOKEN_NULL; |
| } |
| tok->d_update_flag |= FSTAB_UPDATED; |
| } |
| |
| |
| |
| ses = (invt_session_t *) calloc( 1, sizeof( invt_session_t ) ); |
| |
| /* copy the session information to store */ |
| memcpy( &ses->s_sesid, sesid, sizeof( uuid_t ) ); |
| memcpy( &ses->s_fsid, fsid, sizeof( uuid_t ) ); |
| strcpy( ses->s_label, label ); |
| strcpy( ses->s_mountpt, mntpt ); |
| strcpy( ses->s_devpath, devpath ); |
| ses->s_max_nstreams = nstreams; |
| |
| |
| /* s_curstream_off will be set in create_session() */ |
| |
| fd = tok->d_stobj_fd; |
| |
| ASSERT ( fd > 0 ); |
| |
| hdr.sh_time = time; |
| hdr.sh_level = level; |
| /* sh_streams_off and sh_sess_off will be set in create_session() */ |
| |
| sestok = get_sesstoken( tok ); |
| |
| /* we need to put the new session in the appropriate place in |
| storage object. So first find out howmany sessions are there */ |
| |
| INVLOCK( fd, LOCK_EX ); |
| if ( GET_SESCOUNTERS( fd, &sescnt) < 0 ) { |
| free ( ses ); |
| free ( sestok ); |
| INVLOCK( fd, LOCK_UN ); |
| return INV_TOKEN_NULL; |
| } |
| |
| /* create the writesession, and get ready for the streams to come |
| afterwards */ |
| rval = create_session( sestok, fd, sescnt, ses, &hdr ); |
| ASSERT (rval > 0); |
| |
| |
| INVLOCK( fd, LOCK_UN ); |
| |
| sestok->sd_sesstime = time; |
| |
| if ( tok->d_update_flag & NEW_INVINDEX ) { |
| if ( put_sesstime( sestok, INVT_STARTTIME ) < 0 ) { |
| printf ("put_starttime :(\n"); |
| return INV_TOKEN_NULL; |
| } |
| tok->d_update_flag &= ~(NEW_INVINDEX); |
| } |
| |
| free ( ses ); |
| free ( sescnt ); |
| |
| |
| return ( rval < 0 )? INV_TOKEN_NULL: sestok; |
| } |
| |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| |
| bool_t |
| inv_writesession_close( inv_sestoken_t tok ) |
| { |
| int rval; |
| |
| ASSERT ( tok != INV_TOKEN_NULL ); |
| |
| /* now update end_time in the inv index header */ |
| rval = put_sesstime( tok, INVT_ENDTIME ); |
| |
| memset( tok, 0, sizeof( invt_sesdesc_entry_t ) ); |
| |
| free ( tok ); |
| |
| return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; |
| |
| } |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* inventory_stream_open */ |
| /* */ |
| /* Opens a stream for mediafiles to be put in. */ |
| /*----------------------------------------------------------------------*/ |
| inv_stmtoken_t |
| inv_stream_open( |
| inv_sestoken_t tok ) |
| { |
| inv_stmtoken_t stok; |
| invt_stream_t stream; |
| invt_session_t ses; |
| invt_seshdr_t seshdr; |
| int fd; |
| |
| ASSERT ( tok != INV_TOKEN_NULL ); |
| |
| stream.st_nmediafiles = 0; |
| stream.st_interrupted = BOOL_FALSE; |
| |
| |
| /* XXX yukk... make the token descriptors not pointers */ |
| stok = ( inv_stmtoken_t ) malloc( sizeof( invt_strdesc_entry_t ) ); |
| |
| stok->md_sesstok = tok; |
| stok->md_lastmfile = 0; |
| |
| /* get the session to find out where the stream is going to go */ |
| fd = tok->sd_invtok->d_stobj_fd; |
| |
| sess_lock(); |
| |
| INVLOCK( fd, LOCK_SH ); |
| /* get the session header first */ |
| if ( GET_REC_NOLOCK( fd, &seshdr, sizeof( invt_seshdr_t ), |
| tok->sd_sesshdr_off ) <= 0 ) { |
| free ( stok ); |
| INVLOCK( fd, LOCK_UN ); |
| sess_unlock(); |
| return INV_TOKEN_NULL; |
| } |
| |
| |
| |
| /* XXX Have one func that gives both seshdr and session */ |
| if ( GET_REC_NOLOCK( fd, &ses, sizeof( invt_session_t ), |
| tok->sd_session_off ) <= 0 ) { |
| free ( stok ); |
| INVLOCK( fd, LOCK_UN ); |
| sess_unlock(); |
| return INV_TOKEN_NULL; |
| } |
| INVLOCK( fd, LOCK_UN ); |
| |
| if ( ses.s_cur_nstreams < ses.s_max_nstreams ) { |
| /* this is where this stream header will be written to */ |
| stok->md_stream_off = (off64_t) (sizeof( invt_stream_t ) * |
| ses.s_cur_nstreams ) |
| + seshdr.sh_streams_off; |
| ses.s_cur_nstreams++; |
| |
| /* write it back. this locks and unlocks fd EXclusively */ |
| if ( PUT_REC( fd, &ses, sizeof( ses ), |
| tok->sd_session_off ) < 0 ) { |
| free ( stok ); |
| sess_unlock(); |
| return INV_TOKEN_NULL; |
| } |
| } else { |
| fprintf(stderr, "Cant create more than %d streams. Max'd out..\n", |
| ses.s_cur_nstreams ); |
| free ( stok ); |
| sess_unlock(); |
| return INV_TOKEN_NULL; |
| } |
| sess_unlock(); |
| |
| stream.st_firstmfile = stream.st_lastmfile = stok->md_stream_off; |
| |
| /* now put the stream header on to the disk */ |
| if ( PUT_REC( fd, &stream, sizeof( invt_stream_t ), |
| stok->md_stream_off ) < 0 ) { |
| free ( stok ); |
| return INV_TOKEN_NULL; |
| } |
| |
| return stok; |
| } |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| bool_t |
| inv_stream_close( |
| inv_stmtoken_t tok, |
| bool_t wasinterrupted ) |
| { |
| invt_stream_t strm; |
| int fd = tok->md_sesstok->sd_invtok->d_stobj_fd; |
| int rval; |
| bool_t dowrite = BOOL_FALSE; |
| |
| INVLOCK( fd, LOCK_EX ); |
| if ((rval = GET_REC_NOLOCK( fd, &strm, sizeof( invt_stream_t ), |
| tok->md_stream_off )) < 0 ) |
| goto end; /* eek :-) */ |
| |
| if ( strm.st_interrupted != wasinterrupted ) { |
| strm.st_interrupted = wasinterrupted; |
| dowrite = BOOL_TRUE; |
| } |
| |
| /* get the last media file to figure out what our last ino was. |
| we have a pointer to that in the stream token */ |
| if ( tok->md_lastmfile ){ |
| if ( strm.st_endino.ino != tok->md_lastmfile->mf_endino.ino || |
| strm.st_endino.offset != tok->md_lastmfile->mf_endino.offset){ |
| printf("Warning: endinos dont match ! \n"); |
| dowrite = BOOL_TRUE; |
| strm.st_endino = tok->md_lastmfile->mf_endino; |
| } |
| } |
| |
| if (dowrite) { |
| rval = PUT_REC_NOLOCK_SEEKCUR( fd, &strm, sizeof( invt_stream_t ), |
| (off64_t) -(sizeof( invt_stream_t )) ); |
| } |
| end: |
| INVLOCK( fd, LOCK_UN ); |
| |
| free ( tok->md_lastmfile ); |
| memset( tok, 0, sizeof( invt_strdesc_entry_t ) ); |
| free ( tok ); |
| |
| return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; |
| } |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* */ |
| /* */ |
| /* */ |
| /*----------------------------------------------------------------------*/ |
| |
| bool_t |
| inv_put_mediafile( |
| inv_stmtoken_t tok, |
| uuid_t *moid, |
| char *label, |
| xfs_ino_t startino, |
| off64_t startino_offset, |
| xfs_ino_t endino, |
| off64_t endino_offset ) |
| { |
| invt_mediafile_t *mf; |
| int rval; |
| |
| |
| ASSERT ( tok != INV_TOKEN_NULL ); |
| ASSERT ( tok->md_sesstok->sd_invtok->d_update_flag & FSTAB_UPDATED ); |
| ASSERT ( tok->md_sesstok->sd_invtok->d_stobj_fd >= 0 ); |
| |
| mf = (invt_mediafile_t *) calloc( 1, sizeof( invt_mediafile_t ) ); |
| |
| /* copy the media file information */ |
| memcpy( &mf->mf_moid, moid, sizeof( uuid_t ) ); |
| strcpy( mf->mf_label, label ); |
| mf->mf_startino.ino = startino; |
| mf->mf_startino.offset = startino_offset; |
| mf->mf_endino.ino = endino; |
| mf->mf_endino.offset = endino_offset; |
| |
| INVLOCK( tok->md_sesstok->sd_invtok->d_stobj_fd, LOCK_EX ); |
| rval = put_mediafile( tok, mf ); |
| INVLOCK( tok->md_sesstok->sd_invtok->d_stobj_fd, LOCK_UN ); |
| |
| /* we dont free the mfile here. we always keep the last mfile |
| around, inside the inv_stmtoken, and when we add a new mfile, |
| we free the previous one. The last one is freed in stream_close() |
| */ |
| |
| return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; |
| |
| } |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* inv_get_inolist */ |
| /* */ |
| /* This returns all the database files that belong to the inventory, so */ |
| /* that the client (dump) knows that these shouldn't be dumped alongwith*/ |
| /* regular files. */ |
| /* */ |
| /* foreach ( fs in fstab ) */ |
| /* foreach ( index in InvIndex ) */ |
| /* get */ |
| /*----------------------------------------------------------------------*/ |
| |
| intgen_t |
| inv_get_inolist( |
| inv_inolist_t **inolist ) |
| { |
| invt_entry_t *iarr = NULL; |
| invt_counter_t *icnt = NULL; |
| int nindices, i; |
| struct stat64 statbuf; |
| inv_inolist_t *curitem; |
| |
| #ifdef NOTDEF |
| *inolist = NULL; |
| curitem = malloc( sizeof( inv_inolist_t ) ); |
| |
| /* get the array of all indices in the invindex */ |
| if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr, |
| (void **)&icnt, |
| sizeof( invt_entry_t ), |
| sizeof( invt_counter_t )) |
| ) <= 0 ) { |
| return -1; |
| } |
| free( icnt ); |
| |
| /* attach all the StObjs */ |
| for (i = nindices - 1; i >= 0; i--) { |
| if ( stat64( iarr[i].ie_filename, &statbuf ) < 0 ) { |
| perror( iarr[i].ie_filename ); |
| return -1; |
| } |
| |
| create_inolist_item( curitem, statbuf.st_ino ); |
| } |
| /* The inventory index */ |
| if ( fstat64( invfd, &statbuf ) ){ |
| perror( "InvIndex file" ); |
| return -1; |
| } |
| create_inolist_item( curitem, statbuf.st_ino ); |
| |
| /* fstab */ |
| if ( stat64( INV_FSTAB, &statbuf ) < 0 ) { |
| perror( INV_FSTAB ); |
| return -1; |
| } |
| create_inolist_item( curitem, statbuf.st_ino ); |
| |
| /* sesslock file */ |
| if ( stat64( SESSLOCK_FILE, &statbuf ) < 0 ) { |
| perror( SESSLOCK_FILE ); |
| return -1; |
| } |
| create_inolist_item( curitem, statbuf.st_ino ); |
| #endif |
| |
| return 1; |
| |
| } |
| |
| |
| |
| |
| |
| /*----------------------------------------------------------------------*/ |
| /* inv_get_session */ |
| /* */ |
| /* This is to be called after a write-session is complete, but before it*/ |
| /* is closed. ie. the token must still be valid, and all the streams */ |
| /* and their mediafiles put in the inventory. */ |
| /* */ |
| /* On return, the buffer will be filled with all the data pertinent to */ |
| /* the session referred to by the session token. The application of this*/ |
| /* is to dump the inventory of a session to a media object. */ |
| /*----------------------------------------------------------------------*/ |
| |
| bool_t |
| inv_get_session( |
| inv_sestoken_t tok, |
| void **bufpp, /* buf to fill */ |
| size_t *bufszp )/* size of that buffer */ |
| { |
| ASSERT( tok != INV_TOKEN_NULL ); |
| ASSERT( tok->sd_invtok ); |
| |
| /* First get the session header, and the session information. Then |
| we can figure out how much space to allocate */ |
| |
| } |
| |
| |
| |
| |
| #ifdef DEBUG |
| |
| /* This prints out all the sessions of a filesystem that are in the inventory */ |
| bool_t |
| inv_DEBUG_printallsessions( |
| inv_idbtoken_t tok, |
| inv_session_t **ses ) |
| { |
| int rval; |
| rval = search_invt( tok, 0, (void **) ses, |
| (search_callback_t) DEBUG_displayallsessions ); |
| |
| return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; |
| |
| } |
| |
| #endif |