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);
197 char base_filename[PATH_MAX] =
"";
198 snprintf(base_filename,
sizeof(base_filename),
"%s/file.%u",
200 snprintf(filename,
sizeof(filename),
"%s", base_filename);
203 file_fd = open(filename, O_CREAT | O_TRUNC |
O_NOFOLLOW | O_WRONLY,
207 SCLogWarning(
"Filestore (v2) failed to create %s: %s", filename, strerror(errno));
211 if (
SC_ATOMIC_GET(filestore_open_file_cnt) < FileGetMaxOpenFiles()) {
215 if (FileGetMaxOpenFiles() > 0) {
221 }
else if (data != NULL) {
223 file_fd = open(filename, O_APPEND |
O_NOFOLLOW | O_WRONLY);
236 ssize_t r = write(file_fd, (
const void *)data, (
size_t)data_len);
257 OutputFilestoreFinalizeFiles(
tv, aft, ctx, p, ff, tx, tx_id, dir);
271 if (initdata == NULL) {
272 SCLogDebug(
"Error getting context for LogFileStore. \"initdata\" argument NULL");
306 static void OutputFilestoreLogDeInitCtx(
OutputCtx *output_ctx)
316 static void GetLogDirectory(
const ConfNode *conf,
char *out,
size_t out_size)
319 if (log_base_dir == NULL) {
320 SCLogConfig(
"Filestore (v2) default log directory %s", default_log_dir);
321 log_base_dir = default_log_dir;
324 strlcpy(out, log_base_dir, out_size);
327 snprintf(out, out_size,
"%s/%s", default_log_prefix, log_base_dir);
331 static bool InitFilestoreDirectory(
const char *dir)
333 const uint8_t dir_count = 0xff;
336 SCLogInfo(
"Filestore (v2) creating directory %s", dir);
338 SCLogError(
"Filestore (v2) failed to create directory %s: %s", dir, strerror(errno));
343 for (
int i = 0; i <= dir_count; i++) {
345 int n = snprintf(leaf,
sizeof(leaf),
"%s/%02x", dir, i);
346 if (n < 0 || n >= PATH_MAX) {
347 SCLogError(
"Filestore (v2) failed to create leaf directory: "
352 SCLogInfo(
"Filestore (v2) creating directory %s", leaf);
355 "Filestore (v2) failed to create directory %s: %s", leaf, strerror(errno));
362 char tmpdir[PATH_MAX];
363 int n = snprintf(tmpdir,
sizeof(tmpdir),
"%s/tmp", dir);
364 if (n < 0 || n >= PATH_MAX) {
365 SCLogError(
"Filestore (v2) failed to create tmp directory: path too long");
369 SCLogInfo(
"Filestore (v2) creating directory %s", tmpdir);
371 SCLogError(
"Filestore (v2) failed to create directory %s: %s", tmpdir, strerror(errno));
389 SCLogWarning(
"File-store v1 has been removed. Please update to file-store v2.");
394 SCLogWarning(
"A file data logger is already enabled. Filestore (v2) "
395 "will not be enabled.");
399 char log_directory[PATH_MAX] =
"";
400 GetLogDirectory(conf, log_directory,
sizeof(log_directory));
401 if (!InitFilestoreDirectory(log_directory)) {
411 int written = snprintf(ctx->
tmpdir,
sizeof(ctx->
tmpdir) - 1,
"%s/tmp",
413 if (written ==
sizeof(ctx->
tmpdir)) {
414 SCLogError(
"File-store output directory overflow.");
430 output_ctx->
data = ctx;
431 output_ctx->
DeInit = OutputFilestoreLogDeInitCtx;
435 if (write_fileinfo != NULL &&
ConfValIsTrue(write_fileinfo)) {
436 SCLogConfig(
"Filestore (v2) will output fileinfo records.");
442 if (force_filestore != NULL &&
ConfValIsTrue(force_filestore)) {
444 SCLogInfo(
"forcing filestore of all files");
450 SCLogConfig(
"Filestore (v2) forcing magic lookup for stored files");
462 if (stream_depth_str != NULL && strcmp(stream_depth_str,
"no")) {
463 uint32_t stream_depth = 0;
465 &stream_depth) < 0) {
467 "file-store.stream-depth "
468 "from conf file - %s. Killing engine",
474 SCLogWarning(
"file-store.stream-depth value %" PRIu32
" has "
475 "no effect since it's less than stream.reassembly.depth "
486 if (file_count_str != NULL) {
487 uint32_t file_count = 0;
491 "file-store.max-open-files "
492 "from conf file - %s. Killing engine",
496 if (file_count != 0) {
497 FileSetMaxOpenFiles(file_count);
498 SCLogConfig(
"Filestore (v2) will keep a max of %d "
499 "simultaneously open files", file_count);
504 result.
ctx = output_ctx;
512 OutputFilestoreLogInitCtx, OutputFilestoreLogger,
513 OutputFilestoreLogThreadInit, OutputFilestoreLogThreadDeinit,