|
Packit |
8ea169 |
/*
|
|
Packit |
8ea169 |
Copyright (C) 2013 ABRT Team
|
|
Packit |
8ea169 |
Copyright (C) 2013 RedHat inc.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
(at your option) any later version.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
GNU General Public License for more details.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
You should have received a copy of the GNU General Public License along
|
|
Packit |
8ea169 |
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
8ea169 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#include "internal_libabrt.h"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
#define IGN_COLUMN_DELIMITER ';'
|
|
Packit |
8ea169 |
#define IGN_DD_OPEN_FLAGS (DD_OPEN_READONLY | DD_FAIL_QUIETLY_ENOENT | DD_FAIL_QUIETLY_EACCES)
|
|
Packit |
8ea169 |
#define IGN_DD_LOAD_TEXT_FLAGS (DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE | DD_FAIL_QUIETLY_ENOENT | DD_FAIL_QUIETLY_EACCES)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
struct ignored_problems
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *ign_set_file_path;
|
|
Packit |
8ea169 |
};
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
ignored_problems_t *ignored_problems_new(char *set_file_path)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
ignored_problems_t *set = xmalloc(sizeof(*set));
|
|
Packit |
8ea169 |
set->ign_set_file_path = set_file_path;
|
|
Packit |
8ea169 |
return set;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ignored_problems_free(ignored_problems_t *set)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (!set)
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
free(set->ign_set_file_path);
|
|
Packit |
8ea169 |
free(set);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool ignored_problems_eq(ignored_problems_t *set,
|
|
Packit |
8ea169 |
const char *problem_id, const char *uuid, const char *duphash,
|
|
Packit |
8ea169 |
const char *line, unsigned line_num)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
const char *ignored = line;
|
|
Packit |
8ea169 |
const char *ignored_end = strchrnul(ignored, IGN_COLUMN_DELIMITER);
|
|
Packit |
8ea169 |
size_t sz = ignored_end - ignored;
|
|
Packit |
8ea169 |
if (strncmp(problem_id, ignored, sz) == 0 && problem_id[sz] == '\0')
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Ignored id matches '%s'", problem_id);
|
|
Packit |
8ea169 |
return true;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (ignored_end[0] == '\0')
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("No 2nd column (UUID) at line %d in ignored problems file '%s'",
|
|
Packit |
8ea169 |
line_num, set->ign_set_file_path);
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
ignored = ignored_end + 1;
|
|
Packit |
8ea169 |
ignored_end = strchrnul(ignored, IGN_COLUMN_DELIMITER);
|
|
Packit |
8ea169 |
sz = ignored_end - ignored;
|
|
Packit |
8ea169 |
if (uuid != NULL && strncmp(uuid, ignored, sz) == 0 && uuid[sz] == '\0')
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Ignored uuid '%s' matches uuid of problem '%s'", ignored, problem_id);
|
|
Packit |
8ea169 |
return true;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (ignored_end[0] == '\0')
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("No 3rd column (DUPHASH) at line %d in ignored problems file '%s'",
|
|
Packit |
8ea169 |
line_num, set->ign_set_file_path);
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
ignored = ignored_end + 1;
|
|
Packit |
8ea169 |
ignored_end = strchrnul(ignored, IGN_COLUMN_DELIMITER);
|
|
Packit |
8ea169 |
sz = ignored_end - ignored;
|
|
Packit |
8ea169 |
if (duphash != NULL && strncmp(duphash, ignored, sz) == 0 && duphash[sz] == '\0')
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Ignored duphash '%s' matches duphash of problem '%s'", ignored, problem_id);
|
|
Packit |
8ea169 |
return true;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static bool ignored_problems_file_contains(ignored_problems_t *set,
|
|
Packit |
8ea169 |
const char *problem_id, const char *uuid, const char *duphash,
|
|
Packit |
8ea169 |
FILE **out_fp, const char *mode)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
bool found = false;
|
|
Packit |
8ea169 |
FILE *fp = fopen(set->ign_set_file_path, mode);
|
|
Packit |
8ea169 |
if (!fp)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (errno != ENOENT)
|
|
Packit |
8ea169 |
pwarn_msg("Can't open ignored problems '%s' in mode '%s'", set->ign_set_file_path, mode);
|
|
Packit |
8ea169 |
goto ret_contains_end;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
unsigned line_num = 0;
|
|
Packit |
8ea169 |
while (!found)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *line = xmalloc_fgetline(fp);
|
|
Packit |
8ea169 |
if (!line)
|
|
Packit |
8ea169 |
break;
|
|
Packit |
8ea169 |
++line_num;
|
|
Packit |
8ea169 |
found = ignored_problems_eq(set, problem_id, uuid, duphash, line, line_num);
|
|
Packit |
8ea169 |
free(line);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
ret_contains_end:
|
|
Packit |
8ea169 |
if (out_fp)
|
|
Packit |
8ea169 |
*out_fp = fp;
|
|
Packit |
8ea169 |
else if (fp)
|
|
Packit |
8ea169 |
fclose(fp);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return found;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
static void ignored_problems_add_row(ignored_problems_t *set, const char *problem_id,
|
|
Packit |
8ea169 |
const char *uuid, const char *duphash)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Going to add problem '%s' to ignored problems", problem_id);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
FILE *fp;
|
|
Packit |
8ea169 |
if (!ignored_problems_file_contains(set, problem_id, uuid, duphash, &fp, "a+"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (fp)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* We can add write error checks here.
|
|
Packit |
8ea169 |
* However, what exactly can we *do* if we detect it?
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
fprintf(fp, "%s;%s;%s\n", problem_id, (uuid ? uuid : ""),
|
|
Packit |
8ea169 |
(duphash ? duphash : ""));
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* This is not a fatal problem. We are permissive because we don't want
|
|
Packit |
8ea169 |
* to scare users by strange error messages.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
log_notice("Can't add problem '%s' to ignored problems:"
|
|
Packit |
8ea169 |
" can't open the list", problem_id);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Won't add problem '%s' to ignored problems:"
|
|
Packit |
8ea169 |
" it is already there", problem_id);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (fp)
|
|
Packit |
8ea169 |
fclose(fp);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ignored_problems_add_problem_data(ignored_problems_t *set, problem_data_t *pd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
ignored_problems_add_row(set,
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, CD_DUMPDIR),
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, FILENAME_UUID),
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, FILENAME_DUPHASH)
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ignored_problems_add(ignored_problems_t *set, const char *problem_id)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(problem_id, IGN_DD_OPEN_FLAGS);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* We do not consider this as an error because the directory can be
|
|
Packit |
8ea169 |
* deleted by other programs. This code expects that dd_opendir()
|
|
Packit |
8ea169 |
* already emitted good explanatory message. This message
|
|
Packit |
8ea169 |
* explains what the previous failure causes.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
VERB1 log_warning("Can't add problem '%s' to ignored problems:"
|
|
Packit |
8ea169 |
" can't open the problem", problem_id);
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
char *uuid = dd_load_text_ext(dd, FILENAME_UUID, IGN_DD_LOAD_TEXT_FLAGS);
|
|
Packit |
8ea169 |
char *duphash = dd_load_text_ext(dd, FILENAME_DUPHASH, IGN_DD_LOAD_TEXT_FLAGS);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
ignored_problems_add_row(set, problem_id, uuid, duphash);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(duphash);
|
|
Packit |
8ea169 |
free(uuid);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ignored_problems_remove_row(ignored_problems_t *set, const char *problem_id,
|
|
Packit |
8ea169 |
const char *uuid, const char *duphash)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
INITIALIZE_LIBABRT();
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
VERB1 log_warning("Going to remove problem '%s' from ignored problems", problem_id);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
FILE *orig_fp;
|
|
Packit |
8ea169 |
if (!ignored_problems_file_contains(set, problem_id, uuid, duphash, &orig_fp, "r"))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
if (orig_fp)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
log_notice("Won't remove problem '%s' from ignored problems:"
|
|
Packit |
8ea169 |
" it is already removed", problem_id);
|
|
Packit |
8ea169 |
/* Close orig_fp here because it looks like much simpler than
|
|
Packit |
8ea169 |
* exetendig the set of goto labels at the end of this function */
|
|
Packit |
8ea169 |
fclose(orig_fp);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* This is not a fatal problem. We are permissive because we don't want
|
|
Packit |
8ea169 |
* to scare users by strange error messages.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
log_notice("Can't remove problem '%s' from ignored problems:"
|
|
Packit |
8ea169 |
" can't open the list", problem_id);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
return;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
/* orig_fp must be valid here because if ignored_problems_file_contains()
|
|
Packit |
8ea169 |
* returned TRUE the function ensures that orig_fp is set to a valid FILE*.
|
|
Packit |
8ea169 |
*
|
|
Packit |
8ea169 |
* But the function moved the file position indicator.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
rewind(orig_fp);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
char *new_tempfile_name = xasprintf("%s.XXXXXX", set->ign_set_file_path);
|
|
Packit |
8ea169 |
int new_tempfile_fd = mkstemp(new_tempfile_name);
|
|
Packit |
8ea169 |
if (new_tempfile_fd < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
perror_msg(_("Can't create temporary file '%s'"), set->ign_set_file_path);
|
|
Packit |
8ea169 |
goto ret_close_files;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
unsigned line_num = 0;
|
|
Packit |
8ea169 |
char *line;
|
|
Packit |
8ea169 |
while ((line = xmalloc_fgetline(orig_fp)) != NULL)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
++line_num;
|
|
Packit |
8ea169 |
if (!ignored_problems_eq(set, problem_id, uuid, duphash, line, line_num))
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
ssize_t len = strlen(line);
|
|
Packit |
8ea169 |
line[len] = '\n';
|
|
Packit |
8ea169 |
if (full_write(new_tempfile_fd, line, len + 1) < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* Probably out of space */
|
|
Packit |
8ea169 |
line[len] = '\0';
|
|
Packit |
8ea169 |
perror_msg(_("Can't write to '%s'."
|
|
Packit |
8ea169 |
" Problem '%s' will not be removed from the ignored"
|
|
Packit |
8ea169 |
" problems '%s'"),
|
|
Packit |
8ea169 |
new_tempfile_name, problem_id, set->ign_set_file_path);
|
|
Packit |
8ea169 |
free(line);
|
|
Packit |
8ea169 |
goto ret_unlink_new;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
free(line);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if (rename(new_tempfile_name, set->ign_set_file_path) < 0)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* Something nefarious happened */
|
|
Packit |
8ea169 |
perror_msg(_("Can't rename '%s' to '%s'. Failed to remove problem '%s'"),
|
|
Packit |
8ea169 |
set->ign_set_file_path, new_tempfile_name, problem_id);
|
|
Packit |
8ea169 |
ret_unlink_new:
|
|
Packit |
8ea169 |
unlink(new_tempfile_name);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
ret_close_files:
|
|
Packit |
8ea169 |
fclose(orig_fp);
|
|
Packit |
8ea169 |
if (new_tempfile_fd >= 0)
|
|
Packit |
8ea169 |
close(new_tempfile_fd);
|
|
Packit |
8ea169 |
free(new_tempfile_name);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ignored_problems_remove_problem_data(ignored_problems_t *set, problem_data_t *pd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
ignored_problems_remove_row(set,
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, CD_DUMPDIR),
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, FILENAME_UUID),
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, FILENAME_DUPHASH)
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
void ignored_problems_remove(ignored_problems_t *set, const char *problem_id)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
char *uuid = NULL;
|
|
Packit |
8ea169 |
char *duphash = NULL;
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(problem_id, IGN_DD_OPEN_FLAGS);
|
|
Packit |
8ea169 |
if (dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
uuid = dd_load_text_ext(dd, FILENAME_UUID, IGN_DD_LOAD_TEXT_FLAGS);
|
|
Packit |
8ea169 |
duphash = dd_load_text_ext(dd, FILENAME_DUPHASH, IGN_DD_LOAD_TEXT_FLAGS);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
else
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* We do not consider this as an error because the directory can be
|
|
Packit |
8ea169 |
* deleted by other programs. This code expects that dd_opendir()
|
|
Packit |
8ea169 |
* already emitted good explanatory message. This message
|
|
Packit |
8ea169 |
* explains what the previous failure causes.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
VERB1 error_msg("Can't get UUID/DUPHASH from"
|
|
Packit |
8ea169 |
" '%s' to remove it from the ignored problems:"
|
|
Packit |
8ea169 |
" can't open the problem", problem_id);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
ignored_problems_remove_row(set, problem_id, uuid, duphash);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(duphash);
|
|
Packit |
8ea169 |
free(uuid);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
bool ignored_problems_contains_problem_data(ignored_problems_t *set, problem_data_t *pd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
return ignored_problems_file_contains(set,
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, CD_DUMPDIR),
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, FILENAME_UUID),
|
|
Packit |
8ea169 |
problem_data_get_content_or_NULL(pd, FILENAME_DUPHASH),
|
|
Packit |
8ea169 |
/* (FILE **) */NULL, "r"
|
|
Packit |
8ea169 |
);
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
bool ignored_problems_contains(ignored_problems_t *set, const char *problem_id)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
struct dump_dir *dd = dd_opendir(problem_id, IGN_DD_OPEN_FLAGS);
|
|
Packit |
8ea169 |
if (!dd)
|
|
Packit |
8ea169 |
{
|
|
Packit |
8ea169 |
/* We do not consider this as an error because the directory can be
|
|
Packit |
8ea169 |
* deleted by other programs. This code expects that dd_opendir()
|
|
Packit |
8ea169 |
* already emitted good and explanatory message. This message attempts
|
|
Packit |
8ea169 |
* to explain what the previous failure causes.
|
|
Packit |
8ea169 |
*/
|
|
Packit |
8ea169 |
VERB1 error_msg("Can't open '%s'."
|
|
Packit |
8ea169 |
" Won't try to check whether it belongs to ignored problems",
|
|
Packit |
8ea169 |
problem_id);
|
|
Packit |
8ea169 |
return false;
|
|
Packit |
8ea169 |
}
|
|
Packit |
8ea169 |
char *uuid = dd_load_text_ext(dd, FILENAME_UUID, IGN_DD_LOAD_TEXT_FLAGS);
|
|
Packit |
8ea169 |
char *duphash = dd_load_text_ext(dd, FILENAME_DUPHASH, IGN_DD_LOAD_TEXT_FLAGS);
|
|
Packit |
8ea169 |
dd_close(dd);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
log_notice("Going to check if problem '%s' is in ignored problems '%s'",
|
|
Packit |
8ea169 |
problem_id, set->ign_set_file_path);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
bool found = ignored_problems_file_contains(set, problem_id, uuid, duphash,
|
|
Packit |
8ea169 |
/* (FILE **) */NULL, "r");
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
free(duphash);
|
|
Packit |
8ea169 |
free(uuid);
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return found;
|
|
Packit |
8ea169 |
}
|