Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

227 lines (190 sloc) 6.752 kB
/*
instrument.c - file and directory instrumentation routines
Copyright (C) 2007, 2008 siliconforks.com
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; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will 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 to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <config.h>
#include "instrument.h"
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "encoding.h"
#include "global.h"
#include "instrument-js.h"
#include "resource-manager.h"
#include "util.h"
static int g_verbose = 0;
static int string_ends_with(const char * s, const char * suffix) {
size_t length = strlen(s);
size_t suffix_length = strlen(suffix);
if (length < suffix_length) {
return 0;
}
return strcasecmp(s + (length - suffix_length), suffix) == 0;
}
static enum FileType get_file_type(const char * file) {
if (string_ends_with(file, ".js")) {
return FILE_TYPE_JS;
}
else if (string_ends_with(file, ".html") || string_ends_with(file, ".htm")) {
return FILE_TYPE_HTML;
}
else {
return FILE_TYPE_OTHER;
}
}
static void check_same_file(const char * file1, const char * file2) {
if (is_same_file(file1, file2)) {
fatal("source and destination are the same");
}
}
static void check_contains_file(const char * file1, const char * file2) {
if (contains_file(file1, file2)) {
fatal("%s contains %s", file1, file2);
}
}
static void instrument_file(const char * source_file, const char * destination_file, const char * id, int instrumenting) {
if (g_verbose) {
printf("Instrumenting file %s\n", id);
}
/* check if they are the same */
char * canonical_source_file = make_canonical_path(source_file);
char * canonical_destination_file = make_canonical_path(destination_file);
check_same_file(canonical_source_file, canonical_destination_file);
free(canonical_source_file);
free(canonical_destination_file);
if (instrumenting) {
enum FileType file_type = get_file_type(source_file);
switch (file_type) {
case FILE_TYPE_OTHER:
case FILE_TYPE_HTML:
copy_file(source_file, destination_file);
break;
case FILE_TYPE_JS:
{
FILE * input = xfopen(source_file, "rb");
FILE * output = xfopen(destination_file, "wb");
Stream * input_stream = Stream_new(0);
Stream * output_stream = Stream_new(0);
Stream_write_file_contents(input_stream, input);
size_t num_characters = input_stream->length;
uint16_t * characters = NULL;
int result = jscoverage_bytes_to_characters(jscoverage_encoding, input_stream->data, input_stream->length, &characters, &num_characters);
if (result == JSCOVERAGE_ERROR_ENCODING_NOT_SUPPORTED) {
fatal("encoding %s not supported", jscoverage_encoding);
}
else if (result == JSCOVERAGE_ERROR_INVALID_BYTE_SEQUENCE) {
fatal("error decoding %s in file %s", jscoverage_encoding, id);
}
jscoverage_instrument_js(id, characters, num_characters, output_stream);
free(characters);
if (fwrite(output_stream->data, 1, output_stream->length, output) != output_stream->length) {
fatal("cannot write to file: %s", destination_file);
}
Stream_delete(input_stream);
Stream_delete(output_stream);
fclose(input);
fclose(output);
}
break;
}
}
else {
copy_file(source_file, destination_file);
}
}
void jscoverage_instrument(const char * source,
const char * destination,
int verbose,
char ** exclude,
int num_exclude,
char ** no_instrument,
int num_no_instrument)
{
assert(source != NULL);
assert(destination != NULL);
g_verbose = verbose;
/* check if they are the same */
check_same_file(source, destination);
/* check if source directory is an ancestor of destination directory */
check_contains_file(source, destination);
/* check that the source exists and is a directory */
struct stat buf;
xstat(source, &buf);
if (! S_ISDIR(buf.st_mode)) {
fatal("not a directory: %s", source);
}
/* if the destination directory exists, check that it is a jscoverage directory */
if (stat(destination, &buf) == 0) {
/* it exists */
if (! S_ISDIR(buf.st_mode)) {
fatal("not a directory: %s", destination);
}
if (! directory_is_empty(destination)) {
char * expected_file = NULL;
if (jscoverage_mozilla) {
char * modules_directory = make_path(destination, "modules");
expected_file = make_path(modules_directory, "jscoverage.jsm");
free(modules_directory);
}
else {
expected_file = make_path(destination, "jscoverage.html");
}
if (stat(expected_file, &buf) == -1) {
fatal("refusing to overwrite directory: %s", destination);
}
free(expected_file);
}
}
else if (errno == ENOENT) {
xmkdir(destination);
}
else {
fatal("cannot stat directory: %s", destination);
}
/* finally: copy the directory */
struct DirListEntry * list = make_recursive_dir_list(source);
for (struct DirListEntry * p = list; p != NULL; p = p->next) {
char * s = make_path(source, p->name);
char * d = make_path(destination, p->name);
/* check if it's on the exclude list */
for (int i = 0; i < num_exclude; i++) {
char * x = make_path(source, exclude[i]);
if (is_same_file(x, s) || contains_file(x, s)) {
free(x);
goto cleanup;
}
free(x);
}
char * dd = make_dirname(d);
mkdirs(dd);
free(dd);
int instrument_this = 1;
/* check if it's on the no-instrument list */
for (int i = 0; i < num_no_instrument; i++) {
char * ni = make_path(source, no_instrument[i]);
if (is_same_file(ni, s) || contains_file(ni, s)) {
instrument_this = 0;
}
free(ni);
}
instrument_file(s, d, p->name, instrument_this);
cleanup:
free(s);
free(d);
}
free_dir_list(list);
}
Jump to Line
Something went wrong with that request. Please try again.