33 #define MODULE_NAME "OutputFilestore"
37 #define SHA256_STRING_LEN (SC_SHA256_LEN * 2)
38 #define LEAF_DIR_MAX_LEN 4
39 #define FILESTORE_PREFIX_MAX (PATH_MAX - SHA256_STRING_LEN - LEAF_DIR_MAX_LEN)
43 static const char *default_log_dir =
"filestore";
73 static thread_local
bool once_errs[
WOT_MAX];
75 #define WARN_ONCE(wot_type, ...) \
77 if (!once_errs[wot_type]) { \
78 once_errs[wot_type] = true; \
79 SCLogWarning(__VA_ARGS__); \
83 static uint64_t OutputFilestoreOpenFilesCounter(
void)
88 static uint32_t g_file_store_max_open_files = 0;
90 static void FileSetMaxOpenFiles(uint32_t count)
92 g_file_store_max_open_files = count;
95 static uint32_t FileGetMaxOpenFiles(
void)
97 return g_file_store_max_open_files;
107 static void OutputFilestoreUpdateFileTime(
const char *src_filename,
108 const char *filename)
111 if (stat(src_filename, &sb) != 0) {
112 SCLogDebug(
"Failed to stat %s: %s", filename, strerror(errno));
115 struct utimbuf utimbuf = {
116 .actime = sb.st_atime,
117 .modtime = sb.st_mtime,
119 if (utime(filename, &utimbuf) != 0) {
120 SCLogDebug(
"Failed to update file timestamps: %s: %s", filename,
135 char tmp_filename[PATH_MAX] =
"";
136 snprintf(tmp_filename,
sizeof(tmp_filename),
"%s/file.%u",
ctx->tmpdir,
139 char final_filename[PATH_MAX] =
"";
140 snprintf(final_filename,
sizeof(final_filename),
"%s/%c%c/%s",
141 ctx->prefix, sha256string[0], sha256string[1], sha256string);
144 OutputFilestoreUpdateFileTime(tmp_filename, final_filename);
145 if (unlink(tmp_filename) != 0) {
150 }
else if (rename(tmp_filename, final_filename) != 0) {
154 if (unlink(tmp_filename) != 0) {
163 char js_metadata_filename[PATH_MAX];
164 if (snprintf(js_metadata_filename,
sizeof(js_metadata_filename),
"%s.%" PRIuMAX
".%u.json",
169 JsonBuilder *js_fileinfo =
171 if (
likely(js_fileinfo != NULL)) {
172 jb_close(js_fileinfo);
173 FILE *out = fopen(js_metadata_filename,
"w");
175 size_t js_len = jb_len(js_fileinfo);
176 fwrite(jb_ptr(js_fileinfo), js_len, 1, out);
179 jb_free(js_fileinfo);
186 void *tx,
const uint64_t tx_id,
const uint8_t *data, uint32_t data_len, uint8_t
flags,
192 char filename[PATH_MAX] =
"";
195 SCLogDebug(
"ff %p, data %p, data_len %u", ff, data, data_len);
198 snprintf(filename,
sizeof(filename),
"%s/file.%u",
ctx->tmpdir, ff->
file_store_id);
199 file_fd = open(filename, O_CREAT | O_TRUNC |
O_NOFOLLOW | O_WRONLY,
203 SCLogWarning(
"Filestore (v2) failed to create %s: %s", filename, strerror(errno));
207 if (
SC_ATOMIC_GET(filestore_open_file_cnt) < FileGetMaxOpenFiles()) {
211 if (FileGetMaxOpenFiles() > 0) {
217 }
else if (data != NULL) {
219 snprintf(filename,
sizeof(filename),
"%s/file.%u",
ctx->tmpdir, ff->
file_store_id);
220 file_fd = open(filename, O_APPEND |
O_NOFOLLOW | O_WRONLY);
233 ssize_t r = write(file_fd, (
const void *)data, (
size_t)data_len);
235 snprintf(filename,
sizeof(filename),
"%s/file.%u",
ctx->tmpdir, ff->
file_store_id);
255 OutputFilestoreFinalizeFiles(
tv, aft,
ctx, p, ff, tx, tx_id, dir);
268 if (initdata == NULL) {
269 SCLogDebug(
"Error getting context for LogFileStore. \"initdata\" argument NULL");
303 static void OutputFilestoreLogDeInitCtx(
OutputCtx *output_ctx)
306 if (
ctx->xff_cfg != NULL) {
313 static void GetLogDirectory(
const ConfNode *conf,
char *out,
size_t out_size)
316 if (log_base_dir == NULL) {
317 SCLogConfig(
"Filestore (v2) default log directory %s", default_log_dir);
318 log_base_dir = default_log_dir;
321 strlcpy(out, log_base_dir, out_size);
324 snprintf(out, out_size,
"%s/%s", default_log_prefix, log_base_dir);
328 static bool InitFilestoreDirectory(
const char *dir)
330 const uint8_t dir_count = 0xff;
333 SCLogInfo(
"Filestore (v2) creating directory %s", dir);
335 SCLogError(
"Filestore (v2) failed to create directory %s: %s", dir, strerror(errno));
340 for (
int i = 0; i <= dir_count; i++) {
342 int n = snprintf(leaf,
sizeof(leaf),
"%s/%02x", dir, i);
343 if (n < 0 || n >= PATH_MAX) {
344 SCLogError(
"Filestore (v2) failed to create leaf directory: "
349 SCLogInfo(
"Filestore (v2) creating directory %s", leaf);
352 "Filestore (v2) failed to create directory %s: %s", leaf, strerror(errno));
359 char tmpdir[PATH_MAX];
360 int n = snprintf(tmpdir,
sizeof(tmpdir),
"%s/tmp", dir);
361 if (n < 0 || n >= PATH_MAX) {
362 SCLogError(
"Filestore (v2) failed to create tmp directory: path too long");
366 SCLogInfo(
"Filestore (v2) creating directory %s", tmpdir);
368 SCLogError(
"Filestore (v2) failed to create directory %s: %s", tmpdir, strerror(errno));
386 SCLogWarning(
"File-store v1 has been removed. Please update to file-store v2.");
391 SCLogWarning(
"A file data logger is already enabled. Filestore (v2) "
392 "will not be enabled.");
396 char log_directory[PATH_MAX] =
"";
397 GetLogDirectory(conf, log_directory,
sizeof(log_directory));
398 if (!InitFilestoreDirectory(log_directory)) {
408 int written = snprintf(
ctx->tmpdir,
sizeof(
ctx->tmpdir) - 1,
"%s/tmp",
410 if (written ==
sizeof(
ctx->tmpdir)) {
411 SCLogError(
"File-store output directory overflow.");
417 if (
ctx->xff_cfg != NULL) {
428 output_ctx->
DeInit = OutputFilestoreLogDeInitCtx;
432 if (write_fileinfo != NULL &&
ConfValIsTrue(write_fileinfo)) {
433 SCLogConfig(
"Filestore (v2) will output fileinfo records.");
434 ctx->fileinfo =
true;
439 if (force_filestore != NULL &&
ConfValIsTrue(force_filestore)) {
441 SCLogInfo(
"forcing filestore of all files");
447 SCLogConfig(
"Filestore (v2) forcing magic lookup for stored files");
459 if (stream_depth_str != NULL && strcmp(stream_depth_str,
"no")) {
460 uint32_t stream_depth = 0;
462 &stream_depth) < 0) {
464 "file-store.stream-depth "
465 "from conf file - %s. Killing engine",
471 SCLogWarning(
"file-store.stream-depth value %" PRIu32
" has "
472 "no effect since it's less than stream.reassembly.depth "
483 if (file_count_str != NULL) {
484 uint32_t file_count = 0;
488 "file-store.max-open-files "
489 "from conf file - %s. Killing engine",
493 if (file_count != 0) {
494 FileSetMaxOpenFiles(file_count);
495 SCLogConfig(
"Filestore (v2) will keep a max of %d "
496 "simultaneously open files", file_count);
501 result.
ctx = output_ctx;
509 OutputFilestoreLogInitCtx, OutputFilestoreLogger, OutputFilestoreLogThreadInit,
510 OutputFilestoreLogThreadDeinit);