1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <fcntl.h>
18#include <stdio.h>
19#include <sys/types.h>
20#include <unistd.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/stat.h>
24#include <sys/errno.h>
25#include "ioshark.h"
26#include "compile_ioshark.h"
27
28extern char *progname;
29
30static struct files_db_s *files_db_buckets[FILE_DB_HASHSIZE];
31static int current_fileno = 1;
32static int num_objects = 0;
33
34static int filename_cache_lookup(char *filename);;
35
36void
37files_db_write_objects(FILE *fp)
38{
39	int i;
40	struct ioshark_file_state st;
41
42	for (i = 0 ; i < FILE_DB_HASHSIZE ; i++) {
43		struct files_db_s *db_node, *s;
44
45		db_node = files_db_buckets[i];
46		while (db_node != NULL) {
47			st.fileno = db_node->fileno;
48			st.size = db_node->size;
49			st.global_filename_ix =
50				db_node->global_filename_ix;
51			if (fwrite(&st, sizeof(st), 1, fp) != 1) {
52				fprintf(stderr,
53					"%s Write error trace.outfile\n",
54					progname);
55				exit(EXIT_FAILURE);
56			}
57			s = db_node;
58			db_node = db_node->next;
59			free(s->filename);
60			free(s);
61		}
62	}
63}
64
65void *files_db_lookup(char *pathname)
66{
67	u_int32_t hash;
68	struct files_db_s *db_node;
69
70	hash = jenkins_one_at_a_time_hash(pathname, strlen(pathname));
71	hash %= FILE_DB_HASHSIZE;
72	db_node = files_db_buckets[hash];
73	while (db_node != NULL) {
74		if (strcmp(db_node->filename, pathname) == 0)
75			break;
76		db_node = db_node->next;
77	}
78	return db_node;
79}
80
81void *files_db_add(char *filename)
82{
83	u_int32_t hash;
84	struct files_db_s *db_node;
85
86	if ((db_node = files_db_lookup(filename)))
87		return db_node;
88	hash = jenkins_one_at_a_time_hash(filename, strlen(filename));
89	hash %= FILE_DB_HASHSIZE;
90	db_node = malloc(sizeof(struct files_db_s));
91	db_node->filename = strdup(filename);
92	db_node->global_filename_ix =
93		filename_cache_lookup(filename);
94	db_node->fileno = current_fileno++;
95	db_node->next = files_db_buckets[hash];
96	db_node->size = 0;
97	files_db_buckets[hash] = db_node;
98	num_objects++;
99	return db_node;
100}
101
102int
103files_db_get_total_obj(void)
104{
105	return num_objects;
106}
107
108static struct ioshark_filename_struct *filename_cache;
109static int filename_cache_num_entries;
110static int filename_cache_size;
111
112void
113init_filename_cache(void)
114{
115	static FILE *filename_cache_fp;
116	struct stat st;
117	int file_exists = 1;
118
119	if (stat("ioshark_filenames", &st) < 0) {
120		if (errno != ENOENT) {
121			fprintf(stderr, "%s Can't stat ioshark_filenames file\n",
122				progname);
123			exit(EXIT_FAILURE);
124		} else {
125			file_exists = 0;
126			filename_cache_num_entries = 0;
127		}
128	} else {
129		filename_cache_num_entries = st.st_size /
130			sizeof(struct ioshark_filename_struct);
131	}
132	if (file_exists) {
133		filename_cache_fp = fopen("ioshark_filenames", "r");
134		if (filename_cache_fp == NULL) {
135			fprintf(stderr, "%s Cannot open ioshark_filenames file\n",
136				progname);
137			exit(EXIT_FAILURE);
138		}
139	}
140	/* Preallocate a fixed size of entries */
141	filename_cache_size = filename_cache_num_entries + 1024;
142	filename_cache = calloc(filename_cache_size,
143				sizeof(struct ioshark_filename_struct));
144	if (filename_cache == NULL) {
145		fprintf(stderr, "%s Can't allocate memory - this is fatal\n",
146			__func__);
147		exit(EXIT_FAILURE);
148	}
149	if (fread(filename_cache,
150		  sizeof(struct ioshark_filename_struct),
151		  filename_cache_num_entries,
152		  filename_cache_fp) != (size_t)filename_cache_num_entries) {
153		fprintf(stderr, "%s Can't read ioshark_filenames file\n",
154			progname);
155		exit(EXIT_FAILURE);
156	}
157	if (file_exists)
158		fclose(filename_cache_fp);
159}
160
161static int
162filename_cache_lookup(char *filename)
163{
164	int ret;
165	int i;
166
167	for (i = 0 ; i < filename_cache_num_entries ; i++) {
168		if (strcmp(filename_cache[i].path, filename) == 0)
169			return i;
170	}
171	if (filename_cache_num_entries >= filename_cache_size) {
172		int newsize;
173
174		/* reallocate the filename cache up first */
175		filename_cache_size += 1024;
176		newsize = filename_cache_size *
177			sizeof(struct ioshark_filename_struct);
178		filename_cache = realloc(filename_cache, newsize);
179		if (filename_cache == NULL) {
180			fprintf(stderr,
181				"%s Can't allocate memory - this is fatal\n",
182				__func__);
183			exit(EXIT_FAILURE);
184		}
185	}
186	strcpy(filename_cache[filename_cache_num_entries].path,
187	       filename);
188	ret = filename_cache_num_entries;
189	filename_cache_num_entries++;
190	return ret;
191}
192
193void
194store_filename_cache(void)
195{
196	static FILE *filename_cache_fp;
197
198	filename_cache_fp = fopen("ioshark_filenames", "w+");
199	if (filename_cache_fp == NULL) {
200		fprintf(stderr, "%s Cannot open ioshark_filenames file\n",
201			progname);
202		exit(EXIT_FAILURE);
203	}
204	if (fwrite(filename_cache,
205		   sizeof(struct ioshark_filename_struct),
206		   filename_cache_num_entries,
207		   filename_cache_fp) != (size_t)filename_cache_num_entries) {
208		fprintf(stderr, "%s Can't read ioshark_filenames file\n",
209			progname);
210		exit(EXIT_FAILURE);
211	}
212	fclose(filename_cache_fp);
213	free(filename_cache);
214}
215
216
217
218