| /* |
| * Copyright (c) 2002 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 <ncurses.h> |
| #include <sys/mman.h> |
| #include <sys/stat.h> |
| |
| #include "types.h" |
| #include "mlog.h" |
| #include "inv_priv.h" |
| #include "getopt.h" |
| |
| #include "invutil.h" |
| #include "cmenu.h" |
| #include "list.h" |
| #include "invidx.h" |
| #include "stobj.h" |
| #include "timeutil.h" |
| |
| invidx_fileinfo_t *invidx_file; |
| int invidx_numfiles; |
| |
| extern stobj_fileinfo_t *stobj_file; |
| extern int stobj_numfiles; |
| |
| static void stobj_makefname_len( char *fname, int fname_len ); |
| |
| menu_ops_t invidx_ops = { |
| NULL, |
| invidx_undelete, |
| NULL, |
| invidx_select, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| invidx_highlight, |
| menu_unhighlight, |
| invidx_commit, |
| invidx_prune, |
| }; |
| |
| |
| /*ARGSUSED*/ |
| int |
| invidx_commit(WINDOW *win, node_t *current, node_t *list) |
| { |
| int i; |
| int idx; |
| int fidx; |
| node_t *n; |
| data_t *d; |
| invt_entry_t *inv_entry; |
| |
| n = current; |
| if(n == NULL || n->data == NULL) |
| return 0; |
| |
| d = ((data_t *)(n->data)); |
| fidx = d->file_idx; |
| inv_entry = invidx_file[fidx].data[d->data_idx]; |
| |
| idx = (int)(((long)inv_entry - (long)invidx_file[fidx].mapaddr - sizeof(invt_counter_t)) / sizeof(invt_entry_t)); |
| |
| |
| if(d->deleted == BOOL_TRUE && d->imported == BOOL_FALSE) { |
| /* shortcut - just close and unlink stobj files */ |
| for(i = 0; i < d->nbr_children; i++) { |
| close_stobj_file(((data_t *)(d->children[i]->data))->file_idx, BOOL_TRUE); |
| } |
| mark_all_children_commited(current); |
| |
| if ( invidx_file[fidx].counter->ic_curnum > 1 ) { |
| memmove(&inv_entry[idx], |
| &inv_entry[idx + 1], |
| (sizeof(invt_entry_t) * (invidx_file[fidx].counter->ic_curnum - idx - 1))); |
| |
| invidx_file[fidx].data[idx]=NULL; |
| for(i = idx + 1; i < invidx_file[fidx].numrecords; i++) { |
| if(invidx_file[fidx].data[i] != NULL) |
| invidx_file[fidx].data[i]--; |
| } |
| } |
| invidx_file[fidx].counter->ic_curnum--; |
| } |
| else if(d->imported == BOOL_TRUE) { |
| int dst_fileidx; |
| int dst_invpos; |
| int dst_invidx; |
| char dst_idxfile[MAXPATHLEN]; |
| struct stat s; |
| char dst_stobjfile[MAXPATHLEN]; |
| char *stobjfile; |
| char cmd[1024]; |
| |
| snprintf(dst_idxfile, sizeof(dst_idxfile), "%s/%s", inventory_path, basename(invidx_file[fidx].name)); |
| |
| /* append if we have the target open already, else write to a possibly new file */ |
| if((dst_fileidx = find_matching_invidxfile(dst_idxfile)) >= 0) { |
| invt_entry_t *dest = NULL; |
| |
| if((dst_invidx = find_overlapping_invidx(dst_fileidx, inv_entry)) >= 0) { |
| char *stobj_filename = NULL; |
| int stobj_fd = -1; |
| int stobj_fileidx; |
| int last_dst_invidx; |
| node_t *tmp_parent; |
| data_t *tmp_d; |
| node_t *dst_n; |
| data_t *dst_d; |
| invt_seshdr_t *hdr; |
| invt_session_t *ses; |
| invt_stream_t *strms; |
| invt_mediafile_t *mfiles; |
| |
| last_dst_invidx = -1; |
| i = d->nbr_children - 1; |
| do { |
| if(dst_invidx != last_dst_invidx) { |
| stobj_fileidx = find_matching_stobjfile(invidx_file[dst_fileidx].data[dst_invidx]->ie_filename); |
| stobj_filename = stobj_file[stobj_fileidx].name; |
| stobj_fd = stobj_file[stobj_fileidx].fd; |
| last_dst_invidx = dst_invidx; |
| } |
| |
| /* for each child of inv_entry, insert into invidx & stobj files */ |
| tmp_d = d->children[i]->data; |
| |
| read_stobj_info(stobj_file[tmp_d->file_idx].fd, |
| i, |
| &hdr, |
| &ses, |
| &strms, |
| &mfiles); |
| |
| insert_stobj_into_stobjfile(dst_fileidx, |
| stobj_filename, |
| stobj_fd, |
| hdr, |
| ses, |
| strms, |
| mfiles); |
| |
| free(hdr); free(ses); free(strms); free(mfiles); |
| |
| if(--i < 0) |
| break; |
| } |
| while((dst_invidx = find_overlapping_invidx(dst_fileidx, inv_entry)) >= 0); |
| |
| mark_all_children_commited(current); |
| |
| /* Clean up the mess we just created */ |
| /* find node for dst_fileidx */ |
| dst_n = find_invidx_node(list, dst_fileidx); |
| tmp_parent = ((data_t *)(dst_n->data))->parent; |
| while(dst_n != NULL) { |
| node_t *tmp_n1; |
| |
| dst_d = dst_n->data; |
| |
| /* close affected invidx file and stobj files */ |
| for(i = 0; i < dst_d->nbr_children; i++) { |
| close_stobj_file(((data_t *)(dst_d->children[i]->data))->file_idx, BOOL_FALSE); |
| } |
| |
| /* free_all_children on that node */ |
| free_all_children(dst_n); |
| tmp_n1 = find_invidx_node(dst_n->next, dst_fileidx); |
| node_free(list_del(dst_n)); |
| dst_n = tmp_n1; |
| } |
| close_invidx(dst_fileidx); |
| |
| /* generate invidx menu for the parent node */ |
| dst_n = generate_invidx_menu(inventory_path, tmp_parent, 1, dst_idxfile); |
| |
| if(dst_n != tmp_parent) { |
| /* mark all its children commited */ |
| mark_all_children_commited(dst_n); |
| } |
| |
| return 0; |
| } |
| else { |
| /* insert new invidx entry, and copy over stobj file */ |
| if(invidx_file[dst_fileidx].counter->ic_curnum >= invidx_file[dst_fileidx].nEntries) { |
| dest = remmap_invidx(dst_fileidx, 1); |
| } |
| |
| dst_invpos = find_invidx_insert_pos(dst_fileidx, inv_entry); |
| if(dst_invpos >= 0) { |
| memmove(invidx_file[dst_fileidx].data[dst_invpos + 1], |
| invidx_file[dst_fileidx].data[dst_invpos], |
| sizeof(*inv_entry) * (invidx_file[dst_fileidx].counter->ic_curnum - dst_invpos)); |
| } |
| else { |
| dest = invidx_file[dst_fileidx].data[invidx_file[dst_fileidx].counter->ic_curnum - 1] + 1; |
| } |
| |
| /* copy new data to mmap */ |
| memmove(dest, inv_entry, sizeof(*inv_entry)); |
| |
| /* increment counter */ |
| invidx_file[dst_fileidx].counter->ic_curnum++; |
| |
| mark_all_children_commited(current); |
| |
| /* shortcut - just copy stobj file over */ |
| stobjfile = get_inventry_stobjfile(d); |
| if(stobjfile == NULL) { |
| put_error("Error: unable to work out stobj filename"); |
| return 0; |
| } |
| |
| snprintf(dst_stobjfile, sizeof(dst_stobjfile), "%s/%s", inventory_path, basename(stobjfile)); |
| |
| if(stat(dst_stobjfile, &s) < 0) { |
| if(errno != ENOENT) { |
| put_error("Error: unable to copy stobj file: stat error"); |
| return 0; |
| } |
| } |
| else { |
| put_error("Error: unable to copy stobj file: file exists"); |
| return 0; |
| } |
| |
| snprintf(cmd, sizeof(cmd), "cp %s %s", stobjfile, dst_stobjfile); |
| if(system(cmd) != 0) { |
| put_error("Error: unable to copy stobj file: cp failed"); |
| return 0; |
| } |
| |
| open_stobj(dst_stobjfile); |
| return 0; |
| } |
| } |
| else { |
| /* no matching inventory index file - just copy entry to a new file */ |
| invt_counter_t cnt; |
| int new_fd; |
| |
| memset(&cnt, 0, sizeof(cnt)); |
| cnt.ic_maxnum = INVT_MAX_INVINDICES; |
| cnt.ic_curnum = 0; |
| cnt.ic_vernum = INV_VERSION; |
| |
| mark_all_children_commited(current); |
| |
| if(stat(dst_idxfile, &s) < 0) { |
| if(errno != ENOENT) { |
| put_error("Error: unable to stat inventory index file"); |
| return 0; |
| } |
| } |
| else { |
| put_error("Error: unable to copy inventory index file: file exists"); |
| return 0; |
| } |
| |
| new_fd = open(dst_idxfile, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); |
| if(new_fd < 0) { |
| put_error("Error: unable to open inventory index file"); |
| return 0; |
| } |
| INVLOCK(new_fd, LOCK_EX); |
| |
| cnt.ic_curnum++; |
| write_n_bytes(new_fd, (char *)&cnt, sizeof(cnt), dst_idxfile); |
| |
| write_n_bytes(new_fd, (char *)inv_entry, sizeof(*inv_entry), dst_idxfile); |
| |
| INVLOCK(new_fd, LOCK_UN); |
| close(new_fd); |
| |
| open_invidx(dst_idxfile); |
| |
| /* shortcut - just copy stobj file over */ |
| stobjfile = get_inventry_stobjfile(d); |
| if(stobjfile == NULL) { |
| put_error("Error: unable to work out stobj filename"); |
| return 0; |
| } |
| |
| snprintf(dst_stobjfile, sizeof(dst_stobjfile), "%s/%s", inventory_path, basename(stobjfile)); |
| |
| if(stat(dst_stobjfile, &s) < 0) { |
| if(errno != ENOENT) { |
| put_error("Error: unable to copy stobj file: stat error"); |
| return 0; |
| } |
| } |
| else { |
| put_error("Error: unable to copy stobj file: file exists"); |
| return 0; |
| } |
| |
| snprintf(cmd, sizeof(cmd), "cp %s %s", stobjfile, dst_stobjfile); |
| if(system(cmd) != 0) { |
| put_error("Error: unable to copy stobj file: cp failed"); |
| return 0; |
| } |
| |
| open_stobj(dst_stobjfile); |
| return 0; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int |
| create_stobjfile(int invidx_fileidx, char *filename, int fname_len, |
| invt_seshdr_t *hdr, invt_session_t *ses, invt_stream_t *strms, |
| invt_mediafile_t *mfiles) |
| { |
| int fd; |
| |
| stobj_makefname_len(filename, fname_len); |
| fd = stobj_create(filename); |
| |
| insert_stobj_into_stobjfile(invidx_fileidx, filename, fd, hdr, ses, strms, mfiles); |
| |
| return fd; |
| } |
| |
| int |
| read_stobj_info(int fd, int idx, invt_seshdr_t **out_hdr, |
| invt_session_t **out_ses, invt_stream_t **out_strms, |
| invt_mediafile_t **out_mfiles) |
| { |
| int i; |
| int nmfiles; |
| invt_seshdr_t *hdr; |
| invt_session_t *ses; |
| invt_stream_t *strms; |
| invt_mediafile_t *mfiles; |
| |
| lseek(fd, STOBJ_OFFSET(idx, 0), SEEK_SET); |
| hdr = malloc(sizeof(*hdr)); |
| read_n_bytes(fd, (char *)hdr, sizeof(*hdr), "stobj file"); |
| |
| lseek(fd, hdr->sh_sess_off, SEEK_SET); |
| ses = malloc(sizeof(*ses)); |
| read_n_bytes(fd, (char *)ses, sizeof(*ses), "stobj file"); |
| |
| if(ses->s_cur_nstreams > 0) { |
| lseek(fd, hdr->sh_streams_off, SEEK_SET); |
| strms = malloc(sizeof(*strms) * ses->s_cur_nstreams); |
| read_n_bytes(fd, (char *)strms, sizeof(*strms) * ses->s_cur_nstreams, "stobj file"); |
| |
| nmfiles = 0; |
| for(i = 0; i < ses->s_cur_nstreams; i++) { |
| nmfiles += strms[i].st_nmediafiles; |
| } |
| |
| if(nmfiles > 0) { |
| mfiles = malloc(sizeof(*mfiles) * nmfiles); |
| read_n_bytes(fd, (char *)mfiles, sizeof(*mfiles) * nmfiles, "stobj file"); |
| } |
| else { |
| mfiles = NULL; |
| } |
| } |
| else { |
| strms = NULL; |
| mfiles = NULL; |
| } |
| |
| *out_hdr = hdr; |
| *out_ses = ses; |
| *out_strms = strms; |
| *out_mfiles = mfiles; |
| |
| return fd; |
| } |
| |
| int |
| delete_stobj_entries(int fd, int deletepos) |
| { |
| invt_sescounter_t sescnt; |
| invt_seshdr_t *hdr; |
| invt_session_t *ses; |
| invt_stream_t *strms; |
| invt_mediafile_t *mfiles; |
| |
| lseek(fd, 0, SEEK_SET); |
| read_n_bytes(fd, (char *)&sescnt, sizeof(sescnt), "stobj file"); |
| |
| read_stobj_info(fd, deletepos, &hdr, &ses, &strms, &mfiles); |
| |
| sescnt.ic_eof = hdr->sh_streams_off; |
| |
| free(hdr); free(ses); free(strms); free(mfiles); |
| |
| sescnt.ic_curnum -= deletepos; |
| lseek(fd, 0, SEEK_SET); |
| write_n_bytes(fd, (char *)&sescnt, sizeof(sescnt), "stobj file"); |
| |
| return 0; |
| } |
| |
| int |
| find_stobj_insert_point(int fd, invt_seshdr_t *hdr) |
| { |
| int i; |
| invt_sescounter_t sescnt; |
| invt_seshdr_t tmphdr; |
| |
| lseek(fd, 0, SEEK_SET); |
| read_n_bytes(fd, (char *)&sescnt, sizeof(sescnt), "stobj file"); |
| |
| for(i = 0; i < sescnt.ic_curnum; i++) { |
| read_n_bytes(fd, (char *)&tmphdr, sizeof(tmphdr), "stobj file"); |
| if(hdr->sh_time <= tmphdr.sh_time) { |
| break; |
| } |
| } |
| |
| return i; |
| } |
| |
| int |
| update_invidx_entry(int fd, char *filename, int stobj_fd) |
| { |
| int i; |
| time32_t start_time; |
| time32_t end_time; |
| invt_counter_t cnt; |
| invt_seshdr_t hdr; |
| invt_sescounter_t sescnt; |
| invt_entry_t entry; |
| off_t first_offset; |
| off_t last_offset; |
| |
| /* find the start and stop in stobj file */ |
| lseek(stobj_fd, 0, SEEK_SET); |
| read_n_bytes(stobj_fd, &sescnt, sizeof(sescnt), "stobj file"); |
| |
| memset(&hdr, 0, sizeof(hdr)); |
| first_offset = STOBJ_OFFSET(0,0); |
| lseek(stobj_fd, first_offset, SEEK_SET); |
| read_n_bytes(stobj_fd, &hdr, sizeof(hdr), "stobj file"); |
| start_time = hdr.sh_time; |
| |
| memset(&hdr, 0, sizeof(hdr)); |
| last_offset = STOBJ_OFFSET((sescnt.ic_curnum - 1), 0); |
| lseek(stobj_fd, last_offset, SEEK_SET); |
| read_n_bytes(stobj_fd, &hdr, sizeof(hdr), "stobj file"); |
| end_time = hdr.sh_time; |
| |
| lseek(fd, 0, SEEK_SET); |
| read_n_bytes(fd, &cnt, sizeof(cnt), "invidx file"); |
| |
| for(i = 0; i < cnt.ic_curnum; i++) { |
| lseek(fd, IDX_HDR_OFFSET(i), SEEK_SET); |
| read_n_bytes(fd, &entry, sizeof(entry), "invidx file"); |
| if(strcmp(entry.ie_filename, filename) == 0) { |
| entry.ie_timeperiod.tp_start = start_time; |
| entry.ie_timeperiod.tp_end = end_time; |
| lseek(fd, IDX_HDR_OFFSET(i), SEEK_SET); |
| write_n_bytes(fd, &entry, sizeof(entry), "invidx file"); |
| return i; |
| } |
| } |
| |
| entry.ie_timeperiod.tp_start = start_time; |
| entry.ie_timeperiod.tp_end = end_time; |
| strcpy(entry.ie_filename, filename); |
| lseek(fd, 0, SEEK_END); |
| write_n_bytes(fd, &entry, sizeof(entry), "invidx file"); |
| |
| cnt.ic_curnum++; |
| lseek(fd, 0, SEEK_SET); |
| write_n_bytes(fd, &cnt, sizeof(cnt), "invidx file"); |
| |
| return i; |
| } |
| |
| int |
| insert_stobj_into_stobjfile(int invidx_fileidx, char *filename, int fd, |
| invt_seshdr_t *hdr, invt_session_t *ses, |
| invt_stream_t *strms, invt_mediafile_t *mfiles) |
| { |
| int i; |
| invt_sescounter_t sescnt; |
| int pos; |
| char *buf; |
| int invidx_fd = invidx_file[invidx_fileidx].fd; |
| |
| if(hdr == NULL || ses == NULL || strms == NULL || mfiles == NULL) |
| return 0; |
| |
| lseek(fd, 0, SEEK_SET); |
| read_n_bytes(fd, (char *)&sescnt, sizeof(sescnt), "stobj file"); |
| |
| pos = find_stobj_insert_point(fd, hdr); |
| |
| /* if stobj file is full, we need to split it */ |
| if(sescnt.ic_curnum >= sescnt.ic_maxnum) { |
| int new_fd; |
| char new_filename[INV_STRLEN]; |
| invt_seshdr_t *s_hdr; |
| invt_session_t *s_ses; |
| invt_stream_t *s_strms; |
| invt_mediafile_t *s_mfiles; |
| |
| new_fd = create_stobjfile(invidx_fileidx, new_filename, sizeof(new_filename), hdr, ses, strms, mfiles); |
| |
| for(i = pos; i < sescnt.ic_curnum; i++) { |
| read_stobj_info(fd, i, &s_hdr, &s_ses, &s_strms, &s_mfiles); |
| |
| insert_stobj_into_stobjfile(invidx_fileidx, new_filename, new_fd, s_hdr, s_ses, s_strms, s_mfiles); |
| |
| free(s_hdr); free(s_ses); free(s_strms); free(s_mfiles); |
| } |
| delete_stobj_entries(fd, pos); |
| update_invidx_entry(invidx_fd, new_filename, new_fd); |
| update_invidx_entry(invidx_fd, filename, fd); |
| |
| return 0; |
| } |
| |
| /* stobj file not full, just insert the entry */ |
| hdr->sh_sess_off = STOBJ_OFFSET( sescnt.ic_maxnum, pos); |
| hdr->sh_streams_off = sescnt.ic_eof; |
| |
| /* for seshdr: malloc buffer, copy new entry into buffer, read file entries into buffer, write the lot out */ |
| buf = malloc(((sescnt.ic_curnum - pos) + 1) * sizeof(invt_seshdr_t)); |
| memmove(buf, hdr, sizeof(invt_seshdr_t)); |
| lseek(fd, STOBJ_OFFSET(pos, 0), SEEK_SET); |
| read_n_bytes(fd, buf + sizeof(invt_seshdr_t), (sescnt.ic_curnum - pos) * sizeof(invt_seshdr_t), "stobj file"); |
| lseek(fd, STOBJ_OFFSET(pos, 0), SEEK_SET); |
| write_n_bytes(fd, buf, ((sescnt.ic_curnum - pos) + 1) * sizeof(invt_seshdr_t), "stobj file"); |
| free(buf); |
| |
| /* for session: malloc buffer, copy new entry into buffer, read file entries into buffer, write the lot out */ |
| buf = malloc(((sescnt.ic_curnum - pos) + 1) * sizeof(invt_session_t)); |
| memmove(buf, ses, sizeof(invt_session_t)); |
| lseek(fd, STOBJ_OFFSET(sescnt.ic_maxnum, pos), SEEK_SET); |
| read_n_bytes(fd, buf + sizeof(invt_session_t), (sescnt.ic_curnum - pos) * sizeof(invt_session_t), "stobj file"); |
| lseek(fd, STOBJ_OFFSET(sescnt.ic_maxnum, pos), SEEK_SET); |
| write_n_bytes(fd, buf, ((sescnt.ic_curnum - pos) + 1) * sizeof(invt_session_t), "stobj file"); |
| free(buf); |
| |
| /* write the streams and mediafile info at the end of the stobj file */ |
| stobj_put_streams(fd, hdr, ses, strms, mfiles); |
| |
| /* update counter */ |
| sescnt.ic_curnum++; |
| sescnt.ic_eof = lseek(fd, 0, SEEK_END); |
| lseek(fd, 0, SEEK_SET); |
| write_n_bytes(fd, (char *)&sescnt, sizeof(sescnt), "stobj file"); |
| |
| /* update the inventory index entry */ |
| update_invidx_entry(invidx_fd, filename, fd); |
| |
| return 0; |
| } |
| |
| static void |
| stobj_makefname_len( char *fname, int fname_len ) |
| { |
| /* come up with a new unique name */ |
| uuid_t fn; |
| char str[UUID_STR_LEN + 1]; |
| |
| uuid_generate( fn ); |
| uuid_unparse( fn, str ); |
| |
| snprintf(fname, fname_len, "%s/%s.StObj", inventory_path, str); |
| } |
| |
| int |
| stobj_create( char *fname ) |
| { |
| int fd; |
| invt_sescounter_t sescnt; |
| |
| /* create the new storage object */ |
| if (( fd = open( fname, O_RDWR | O_EXCL | O_CREAT, S_IRUSR|S_IWUSR )) < 0 ) { |
| return -1; |
| } |
| |
| INVLOCK( fd, LOCK_EX ); |
| fchmod( fd, INV_PERMS ); |
| |
| memset(&sescnt, 0, sizeof(sescnt)); |
| sescnt.ic_vernum = INV_VERSION; |
| sescnt.ic_curnum = 0; /* there are no sessions as yet */ |
| sescnt.ic_maxnum = INVT_STOBJ_MAXSESSIONS; |
| sescnt.ic_eof = SC_EOF_INITIAL_POS; |
| |
| lseek(fd, 0, SEEK_SET); |
| write_n_bytes ( fd, (char *)&sescnt, sizeof(sescnt), "new stobj file" ); |
| |
| INVLOCK( fd, LOCK_UN ); |
| return fd; |
| } |
| |
| intgen_t |
| stobj_put_streams( int fd, invt_seshdr_t *hdr, invt_session_t *ses, |
| invt_stream_t *strms, |
| invt_mediafile_t *mfiles ) |
| { |
| u_int nstm = ses->s_cur_nstreams; |
| off64_t off = hdr->sh_streams_off; |
| off64_t mfileoff= off + (off64_t)( nstm * sizeof( invt_stream_t ) ); |
| u_int nmfiles = 0; |
| u_int i,j; |
| |
| /* fix the offsets in streams */ |
| for ( i = 0; i < nstm; i++ ) { |
| strms[i].st_firstmfile = mfileoff + (off64_t) ((size_t) nmfiles * sizeof( invt_mediafile_t ) ); |
| /* now fix the offsets in mediafiles */ |
| for ( j = 0; j < strms[i].st_nmediafiles; j++ ) { |
| |
| /* no need to fix the last element's next ptr */ |
| if ( j < strms[i].st_nmediafiles - 1 ) |
| mfiles[ nmfiles + j ].mf_nextmf = strms[i].st_firstmfile + (off64_t) ((j+1) * sizeof( invt_mediafile_t )); |
| |
| /* no need to fix the first element's prev ptr */ |
| if ( j ) |
| mfiles[ nmfiles + j ].mf_prevmf = strms[i].st_firstmfile + (off64_t) ((j-1) * sizeof( invt_mediafile_t )); |
| } |
| |
| /* adjust the offsets of the first and the last elements |
| in the mediafile chain */ |
| mfiles[ nmfiles ].mf_prevmf = 0; |
| nmfiles += strms[i].st_nmediafiles; |
| mfiles[ nmfiles - 1 ].mf_nextmf = 0; |
| } |
| |
| /* first put the streams. hdr already points at the right place */ |
| lseek(fd, off, SEEK_SET); |
| write_n_bytes( fd, strms, nstm * sizeof( invt_stream_t ), "stobj file" ); |
| |
| lseek(fd, mfileoff, SEEK_SET); |
| write_n_bytes( fd, mfiles, nmfiles * sizeof( invt_mediafile_t ), "stobj file" ); |
| |
| return 1; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| invidx_select(WINDOW *win, node_t *current, node_t *list) |
| { |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| |
| if(d->expanded == TRUE) { |
| return menu_collapse(win, current, list); |
| } |
| |
| return menu_expand(win, current, list); |
| } |
| |
| /*ARGSUSED*/ |
| int |
| invidx_highlight(WINDOW *win, node_t *current, node_t *list) |
| { |
| static char txt[256]; |
| data_t *d; |
| invt_entry_t *invtentry; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| invtentry = invidx_file[d->file_idx].data[d->data_idx]; |
| |
| wclear(infowin); |
| |
| put_info_header("inventory index entry"); |
| |
| snprintf(txt, sizeof(txt), "path: %s", invtentry->ie_filename); |
| put_info_line(1, txt); |
| |
| snprintf(txt, sizeof(txt), "start: %s", ctime32(&invtentry->ie_timeperiod.tp_start)); |
| txt[strlen(txt) - 1] = '\0'; |
| put_info_line(2, txt); |
| |
| snprintf(txt, sizeof(txt), "end: %s", ctime32(&invtentry->ie_timeperiod.tp_end)); |
| txt[strlen(txt) - 1] = '\0'; |
| put_info_line(3, txt); |
| |
| return FALSE; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| invidx_undelete(WINDOW *win, node_t *current, node_t *list) |
| { |
| node_t *n; |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return BOOL_FALSE; |
| } |
| |
| list_undelete(current, list); |
| |
| d = ((data_t *)(current->data)); |
| n = current->next; |
| while(n != NULL && n->data != NULL && ((data_t *)(n->data))->level > d->level) { |
| ((data_t *)(n->data))->deleted = BOOL_FALSE; |
| ((data_t *)(n->data))->text[0] = ' '; |
| n = n->next; |
| } |
| |
| redraw_screen = BOOL_TRUE; |
| |
| return BOOL_FALSE; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| invidx_prune(char *mountpt, uuid_t *uuidp, time32_t prunetime, node_t *node, node_t *list) |
| { |
| data_t *d; |
| invt_entry_t *invidx_entry; |
| |
| if(node == NULL || node->data == NULL) { |
| return BOOL_FALSE; |
| } |
| d = ((data_t *)(node->data)); |
| |
| invidx_entry = invidx_file[d->file_idx].data[d->data_idx]; |
| if(invidx_entry == NULL) { |
| return BOOL_FALSE; |
| } |
| |
| if(invidx_entry->ie_timeperiod.tp_start < prunetime) { |
| return BOOL_TRUE; |
| } |
| |
| return BOOL_FALSE; |
| } |
| |
| node_t * |
| find_invidx_node(node_t *list, int inv_fileidx) |
| { |
| node_t *n; |
| data_t *d; |
| |
| n = list; |
| while(n != NULL && n->data != NULL) { |
| d = n->data; |
| /* is this an invidx entry we're looking at? */ |
| if(d->ops == &invidx_ops) { |
| if(d->file_idx == inv_fileidx) { |
| return n; |
| } |
| } |
| n = n->next; |
| } |
| |
| return NULL; |
| } |
| |
| char * |
| get_inventry_stobjfile(data_t *d) |
| { |
| data_t *child_data; |
| |
| if(d->nbr_children <= 0) { |
| return NULL; |
| } |
| |
| /* all the children will be from the same stobj file, so we can just |
| get the name for the first */ |
| |
| child_data = d->children[0]->data; |
| |
| return stobj_file[child_data->file_idx].name; |
| } |
| |
| int |
| find_overlapping_invidx(int fidx, invt_entry_t *inv_entry) |
| { |
| int i = 0; |
| invt_entry_t *entry; |
| |
| for(i = 0; i < invidx_file[fidx].numrecords; i++) { |
| entry = invidx_file[fidx].data[i]; |
| if(entry->ie_timeperiod.tp_end < inv_entry->ie_timeperiod.tp_start |
| || entry->ie_timeperiod.tp_start > inv_entry->ie_timeperiod.tp_end) { |
| continue; |
| } |
| return i; |
| } |
| |
| return -1; |
| } |
| |
| int |
| find_invidx_insert_pos(int fidx, invt_entry_t *inv_entry) |
| { |
| int i = 0; |
| invt_entry_t *entry; |
| invt_entry_t *next_entry; |
| |
| for(i = 0; i < invidx_file[fidx].numrecords - 1; i++) { |
| entry = invidx_file[fidx].data[i]; |
| next_entry = invidx_file[fidx].data[i+1]; |
| |
| if(inv_entry->ie_timeperiod.tp_start > entry->ie_timeperiod.tp_end |
| && inv_entry->ie_timeperiod.tp_end < next_entry->ie_timeperiod.tp_start ) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| int |
| find_matching_stobjfile(char *filename) |
| { |
| int i = 0; |
| |
| for(i = 0; i < stobj_numfiles; i++) { |
| if(stobj_file[i].name == NULL) |
| continue; |
| if(strcmp(stobj_file[i].name, filename) == 0) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| int |
| find_matching_invidxfile(char *filename) |
| { |
| int i = 0; |
| |
| for(i = 0; i < invidx_numfiles; i++) { |
| if(invidx_file[i].name == NULL) |
| continue; |
| if(strcmp(invidx_file[i].name, filename) == 0) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| int |
| add_invidx_data(int fidx, invt_entry_t *data) |
| { |
| if(invidx_file[fidx].numrecords == 0) { |
| invidx_file[fidx].data = malloc(sizeof(*invidx_file[fidx].data)); |
| if(invidx_file[fidx].data == NULL) { |
| fprintf(stderr, "%s: internal memory error: invidx data allocation\n", |
| g_programName); |
| exit(1); |
| } |
| } |
| else { |
| invidx_file[fidx].data = realloc(invidx_file[fidx].data, |
| sizeof(*invidx_file[fidx].data) |
| * (invidx_file[fidx].numrecords + 1)); |
| if(invidx_file[fidx].data == NULL) { |
| fprintf(stderr, "%s: internal memory error: invidx data reallocation\n", |
| g_programName); |
| exit(1); |
| } |
| } |
| invidx_file[fidx].data[invidx_file[fidx].numrecords] = data; |
| invidx_file[fidx].numrecords++; |
| |
| return 0; |
| } |
| |
| node_t * |
| generate_invidx_menu(char * inv_path, node_t *startnode, int level, char *idxFileName) |
| { |
| int i; |
| int idx; |
| int len; |
| char *txt; |
| node_t *n; |
| invt_entry_t *invidx_entry; |
| char *stobjname; |
| |
| if((idx = open_invidx(idxFileName)) < 0) { |
| return startnode; |
| } |
| |
| invidx_entry = (invt_entry_t *)( invidx_file[idx].mapaddr + sizeof(invt_counter_t)); |
| |
| n = startnode; |
| for (i=0; i < invidx_file[idx].counter->ic_curnum; i++) { |
| len = strlen(invidx_entry[i].ie_filename) + 54; |
| txt = malloc(len); |
| if(txt == NULL) { |
| fprintf(stderr, "%s: internal memory error: invidx_text\n", g_programName); |
| exit(1); |
| } |
| snprintf(txt, len, " inv file: %s ", basename(invidx_entry[i].ie_filename)); |
| |
| n = list_add(n, node_create(BOOL_TRUE, /* hidden */ |
| BOOL_FALSE, /* expanded */ |
| level, /* level */ |
| BOOL_FALSE, /* deleted */ |
| idx, /* file_idx */ |
| txt, /* text */ |
| &(invidx_ops), /* menu ops */ |
| startnode, /* parent */ |
| NULL, /* children */ |
| 0, /* nbr_children */ |
| i)); /* data_idx */ |
| if(n == NULL) { |
| fprintf(stderr, "%s: internal memory error: list_add: node_create: invidx\n", |
| g_programName); |
| exit(1); |
| } |
| |
| add_invidx_data(idx, &(invidx_entry[i])); |
| stobjname = GetNameOfStobj(inv_path, invidx_entry[i].ie_filename); |
| n = generate_stobj_menu( n, level + 1, stobjname ); |
| free(stobjname); |
| } |
| |
| return n; |
| } |
| |
| int |
| add_invidx(char *name, int fd, int nEntries, char *mapaddr, invt_counter_t *counter) |
| { |
| static int highwatermark = 10; |
| |
| if(invidx_numfiles == 0) { |
| invidx_file = malloc(sizeof(*invidx_file) * highwatermark); |
| if(invidx_file == NULL) { |
| fprintf(stderr, "%s: internal memory error: malloc invidx_file\n", g_programName); |
| exit(1); |
| } |
| } |
| else { |
| if(invidx_numfiles >= highwatermark - 1) { |
| highwatermark += highwatermark; |
| |
| invidx_file = realloc(invidx_file, sizeof(*invidx_file) * highwatermark); |
| if(invidx_file == NULL) { |
| fprintf(stderr, "%s: internal memory error: realloc invidx\n", g_programName); |
| exit(1); |
| } |
| } |
| } |
| |
| invidx_file[invidx_numfiles].nEntries = nEntries; |
| invidx_file[invidx_numfiles].mapaddr = mapaddr; |
| invidx_file[invidx_numfiles].fd = fd; |
| invidx_file[invidx_numfiles].name = name; |
| invidx_file[invidx_numfiles].counter = counter; |
| invidx_file[invidx_numfiles].data = NULL; |
| invidx_file[invidx_numfiles].numrecords = 0; |
| |
| invidx_numfiles++; |
| |
| return invidx_numfiles - 1; |
| } |
| |
| void * |
| remmap_invidx(int fidx, int num) |
| { |
| int i; |
| int nEntries; |
| char *mapaddr; |
| invt_entry_t *inv_entry; |
| |
| nEntries = invidx_file[fidx].counter->ic_curnum; |
| |
| munmap( invidx_file[fidx].mapaddr, |
| (nEntries * sizeof(invt_entry_t)) + sizeof(invt_counter_t)); |
| |
| /* need to lseek on the file to grow it to the right size - no autogrow on linux */ |
| lseek(invidx_file[fidx].fd, (num * sizeof(invt_entry_t)) - 1, SEEK_END); |
| write_n_bytes(invidx_file[fidx].fd, "", 1, invidx_file[fidx].name); |
| |
| mapaddr = mmap_n_bytes(invidx_file[fidx].fd, |
| (nEntries + 1) * (num * sizeof(invt_entry_t)) |
| + sizeof(invt_counter_t), |
| BOOL_FALSE, |
| invidx_file[fidx].name); |
| |
| invidx_file[fidx].nEntries += num; |
| invidx_file[fidx].mapaddr = mapaddr; |
| invidx_file[fidx].counter = (invt_counter_t *)mapaddr; |
| |
| /* regenerate the data index for the file given the new mapping */ |
| inv_entry = (invt_entry_t *)(invidx_file[fidx].mapaddr + sizeof(invt_counter_t)); |
| for(i=0; i < nEntries; i++) { |
| if(i >= invidx_file[fidx].numrecords) { |
| add_invidx_data(fidx, &(inv_entry[i])); |
| } |
| else { |
| invidx_file[fidx].data[i] = &(inv_entry[i]); |
| } |
| } |
| |
| return &(inv_entry[i]); |
| } |
| |
| int |
| open_invidx(char *idxFileName) |
| { |
| int fd; |
| int nEntries; |
| char *mapaddr; |
| char *name; |
| invt_counter_t header; |
| |
| errno=0; |
| fd = open_and_lock( idxFileName, FILE_WRITE, wait_for_locks ); |
| if (fd < 0) { |
| return fd; |
| } |
| |
| name = strdup(idxFileName); |
| if(name == NULL) { |
| fprintf(stderr, "%s: internal memory error: strdup idxFileName\n", g_programName); |
| exit(1); |
| } |
| |
| read_n_bytes( fd, &header, sizeof(invt_counter_t), idxFileName); |
| |
| nEntries = header.ic_curnum; |
| |
| mapaddr = mmap_n_bytes(fd, |
| nEntries*sizeof(invt_entry_t) + sizeof(invt_counter_t), |
| BOOL_FALSE, |
| idxFileName); |
| |
| return add_invidx(name, fd, nEntries, mapaddr, (invt_counter_t *)mapaddr); |
| } |
| |
| |
| int |
| close_invidx(int idx) |
| { |
| int nEntries; |
| |
| if(idx >= invidx_numfiles || invidx_file[idx].fd < 0) |
| return 0; |
| |
| nEntries = invidx_file[idx].counter->ic_curnum; |
| munmap( invidx_file[idx].mapaddr, |
| (invidx_file[idx].nEntries*sizeof(invt_entry_t)) + sizeof(invt_counter_t) ); |
| |
| if(nEntries != 0 && nEntries != invidx_file[idx].nEntries) { |
| ftruncate(invidx_file[idx].fd, |
| sizeof(invt_counter_t) + (nEntries * sizeof(invt_entry_t)) ); |
| } |
| |
| close( invidx_file[idx].fd ); |
| |
| if(nEntries == 0) { |
| unlink(invidx_file[idx].name); |
| } |
| free( invidx_file[idx].name ); |
| free( invidx_file[idx].data ); |
| |
| invidx_file[idx].fd = -1; |
| invidx_file[idx].name = NULL; |
| invidx_file[idx].data = NULL; |
| |
| return 0; |
| } |
| |
| int |
| close_all_invidx() |
| { |
| int i; |
| |
| for(i = 0; i < invidx_numfiles; i++) { |
| if(invidx_file[i].fd < 0) |
| continue; |
| close_invidx(i); |
| } |
| |
| free(invidx_file); |
| invidx_file = NULL; |
| return 0; |
| } |