static void PathConcatImpl(PathBuffer* buffer, const T* other) { CHECK(!PathIsAbsolute(other)); int seg_count = buffer->m_SegCount; int min_seg_count = (buffer->m_Flags & PathBuffer::kFlagWindowsDevicePath) ? 1 : 0; // Start by throwing away .. from the other path for (int i = 0, count = other->m_LeadingDotDots; i < count; ++i) { if (seg_count > min_seg_count) { seg_count--; } else if (seg_count == 0) { buffer->m_LeadingDotDots++; } } // Can't go higher than root directory. Just clamp to there. if (PathIsAbsolute(buffer)) { buffer->m_LeadingDotDots = 0; } // Compute how much of our data buffer we need to keep int keep_buffer = BufferSize(buffer, seg_count); // Compute size of the other buffer. int other_buffer = BufferSize(other, other->m_SegCount); CHECK(seg_count + other->m_SegCount <= kMaxPathSegments); CHECK(keep_buffer + other_buffer <= kMaxPathLength); memcpy(buffer->m_Data + keep_buffer, other->m_Data, other_buffer); for (int i = 0, count = other->m_SegCount; i < count; ++i) { buffer->m_SegEnds[seg_count + i] = uint16_t(other->m_SegEnds[i] + keep_buffer); } buffer->m_SegCount = uint16_t(seg_count + other->m_SegCount); }
void PathConcat(PathBuffer* buffer, const PathBuffer* other) { if (PathIsAbsolute(other)) { *buffer = *other; } else { PathConcatImpl(buffer, other); } }
/** \brief Create a new http log LogFilestoreCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful * */ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) { LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("Could not create new LogFilestoreCtx"); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; output_ctx->data = NULL; output_ctx->DeInit = LogFilestoreLogDeInitCtx; char *s_default_log_dir = NULL; s_default_log_dir = ConfigGetLogDirectory(); const char *s_base_dir = NULL; s_base_dir = ConfNodeLookupChildValue(conf, "log-dir"); if (s_base_dir == NULL || strlen(s_base_dir) == 0) { strlcpy(g_logfile_base_dir, s_default_log_dir, sizeof(g_logfile_base_dir)); } else { if (PathIsAbsolute(s_base_dir)) { strlcpy(g_logfile_base_dir, s_base_dir, sizeof(g_logfile_base_dir)); } else { snprintf(g_logfile_base_dir, sizeof(g_logfile_base_dir), "%s/%s", s_default_log_dir, s_base_dir); } } const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for stored files"); } const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); if (force_md5 != NULL && ConfValIsTrue(force_md5)) { #ifdef HAVE_NSS FileForceMd5Enable(); SCLogInfo("forcing md5 calculation for stored files"); #else SCLogInfo("md5 calculation requires linking against libnss"); #endif } SCLogInfo("storing files in %s", g_logfile_base_dir); SCReturnPtr(output_ctx, "OutputCtx"); }
static void PathToAbsolute(TCHAR *pOut, size_t outSize, const TCHAR *pSrc) { if (PathIsAbsolute(pSrc) || !isalnum(pSrc[0])) mir_tstrncpy(pOut, pSrc, (int)outSize); else { if (dbPath[0] == _T('\0')) { char tmp[1024]; CallService(MS_DB_GETPROFILEPATH, _countof(tmp), (LPARAM)tmp); mir_sntprintf(dbPath, _T("%S\\"), tmp); } mir_sntprintf(pOut, outSize, _T("%s%s"), dbPath, pSrc); } }
static void PathToRelative(TCHAR *pOut, size_t outSize, const TCHAR *pSrc) { if (!PathIsAbsolute(pSrc)) mir_tstrncpy(pOut, pSrc, (int)outSize); else { if (dbPath[0] == _T('\0')) { char tmp[1024]; CallService(MS_DB_GETPROFILEPATH, _countof(tmp), (LPARAM)tmp); mir_sntprintf(dbPath, _T("%S\\"), tmp); } size_t len = mir_tstrlen(dbPath); if (!_tcsnicmp(pSrc, dbPath, len)) len = 0; mir_tstrncpy(pOut, pSrc + len, outSize); } }
MIR_CORE_DLL(int) PathToRelative(const char *pSrc, char *pOut, const char *pBase) { if (!pSrc || !pSrc[0] || strlen(pSrc) > MAX_PATH) return 0; if (!PathIsAbsolute(pSrc)) strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); else { if (pBase == NULL) pBase = szMirandaPath; size_t cbBaseLen = strlen(pBase); if (!strnicmp(pSrc, pBase, cbBaseLen)) strncpy_s(pOut, MAX_PATH, pSrc + cbBaseLen, _TRUNCATE); else strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); } return (int)strlen(pOut); }
MIR_CORE_DLL(int) PathToAbsolute(const char *pSrc, char *pOut, const char *base) { if (!pSrc || !pSrc[0] || strlen(pSrc) > MAX_PATH) { *pOut = 0; return 0; } char buf[MAX_PATH]; if (pSrc[0] < ' ') strncpy_s(pOut, MAX_PATH, pSrc, _TRUNCATE); if (PathIsAbsolute(pSrc)) return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL); if (base == NULL) base = szMirandaPath; if (pSrc[0] == '\\') pSrc++; mir_snprintf(buf, "%s%s", base, pSrc); return GetFullPathNameA(buf, _countof(buf), pOut, NULL); }
/** \brief open a generic output "log file", which may be a regular file or a socket * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode * \param rotate Register the file for rotation in HUP. * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate) { char log_path[PATH_MAX]; char *log_dir; const char *filename, *filetype; // Arg check if (conf == NULL || log_ctx == NULL || default_filename == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " "missing an argument", conf, log_ctx, default_filename); return -1; } if (log_ctx->fp != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric: previously initialized Log CTX " "encountered"); return -1; } // Resolve the given config filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) filename = default_filename; log_dir = ConfigGetLogDirectory(); if (PathIsAbsolute(filename)) { snprintf(log_path, PATH_MAX, "%s", filename); } else { snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; const char *append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { /* Don't bail. May be able to connect later. */ log_ctx->is_sock = 1; log_ctx->sock_type = SOCK_STREAM; log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1); } else if (strcasecmp(filetype, "unix_dgram") == 0) { /* Don't bail. May be able to connect later. */ log_ctx->is_sock = 1; log_ctx->sock_type = SOCK_DGRAM; log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || strcasecmp(filetype, "file") == 0) { log_ctx->fp = SCLogOpenFileFp(log_path, append); if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine log_ctx->is_regular = 1; if (rotate) { OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); } } else if (strcasecmp(filetype, "pcie") == 0) { log_ctx->pcie_fp = SCLogOpenPcieFp(log_ctx, log_path, append); if (log_ctx->pcie_fp == NULL) return -1; // Error already logged by Open...Fp routine #ifdef HAVE_LIBHIREDIS } else if (strcasecmp(filetype, "redis") == 0) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); if (SCConfLogOpenRedis(redis_node, log_ctx) < 0) { SCLogError(SC_ERR_REDIS, "failed to open redis output"); return -1; } log_ctx->type = LOGFILE_TYPE_REDIS; #endif } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.filetype. Expected \"regular\" (default), \"unix_stream\", " "\"pcie\" " "or \"unix_dgram\"", conf->name); } log_ctx->filename = SCStrdup(log_path); if (unlikely(log_ctx->filename == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for filename"); return -1; } SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); return 0; }
/** \brief open a generic output "log file", which may be a regular file or a socket * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename) { char log_path[PATH_MAX]; char *log_dir; const char *filename, *filetype; // Arg check if (conf == NULL || log_ctx == NULL || default_filename == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " "missing an argument", conf, log_ctx, default_filename); return -1; } if (log_ctx->fp != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric: previously initialized Log CTX " "encountered"); return -1; } // Resolve the given config filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) filename = default_filename; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; if (PathIsAbsolute(filename)) { snprintf(log_path, PATH_MAX, "%s", filename); } else { snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; #ifdef __tile__ log_ctx->filetype = regular; #endif // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM); #ifdef __tile__ log_ctx->filetype = unix_stream; #endif } else if (strcasecmp(filetype, "unix_dgram") == 0) { log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM); #ifdef __tile__ log_ctx->filetype = unix_dgram; #endif } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0) { const char *append; append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; log_ctx->fp = SCLogOpenFileFp(log_path, append); #ifdef __tile__ } else if (strcasecmp(filetype, "tile_pcie") == 0) { const char *append; append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; log_ctx->pcie_ctx = SCLogOpenPcieFileFp(log_path, append); log_ctx->filetype = tile_pcie; #endif } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.type. Expected \"regular\" (default), \"unix_stream\" " "or \"unix_dgram\"", conf->name); } #ifdef __tile__ if (log_ctx->filetype == tile_pcie) { if (log_ctx->pcie_ctx == NULL) return -1; // Error already logged by Open...Fp routine } else { if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine } #else if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine #endif SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); return 0; }
/** \brief Create a new http log LogFilestoreCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful * */ static OutputInitResult LogFilestoreLogInitCtx(ConfNode *conf) { OutputInitResult result = { NULL, false }; intmax_t version = 0; if (ConfGetChildValueInt(conf, "version", &version)) { if (version > 1) { result.ok = true; return result; } } if (RunModeOutputFiledataEnabled()) { SCLogWarning(SC_ERR_NOT_SUPPORTED, "A file data logger is already enabled. Filestore (v1) " "will not be enabled."); return result; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return result; output_ctx->data = NULL; output_ctx->DeInit = LogFilestoreLogDeInitCtx; const char *s_default_log_dir = NULL; s_default_log_dir = ConfigGetLogDirectory(); const char *s_base_dir = NULL; s_base_dir = ConfNodeLookupChildValue(conf, "log-dir"); if (s_base_dir == NULL || strlen(s_base_dir) == 0) { strlcpy(g_logfile_base_dir, s_default_log_dir, sizeof(g_logfile_base_dir)); } else { if (PathIsAbsolute(s_base_dir)) { strlcpy(g_logfile_base_dir, s_base_dir, sizeof(g_logfile_base_dir)); } else { snprintf(g_logfile_base_dir, sizeof(g_logfile_base_dir), "%s/%s", s_default_log_dir, s_base_dir); } } const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { FileForceFilestoreEnable(); SCLogInfo("forcing filestore of all files"); } const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for stored files"); } const char *write_meta = ConfNodeLookupChildValue(conf, "write-meta"); if (write_meta != NULL && !ConfValIsTrue(write_meta)) { FileWriteMetaDisable(); SCLogInfo("File-store output will not write meta files"); } FileForceHashParseCfg(conf); SCLogInfo("storing files in %s", g_logfile_base_dir); const char *stream_depth_str = ConfNodeLookupChildValue(conf, "stream-depth"); if (stream_depth_str != NULL && strcmp(stream_depth_str, "no")) { uint32_t stream_depth = 0; if (ParseSizeStringU32(stream_depth_str, &stream_depth) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " "file-store.stream-depth " "from conf file - %s. Killing engine", stream_depth_str); exit(EXIT_FAILURE); } else { FileReassemblyDepthEnable(stream_depth); } } const char *file_count_str = ConfNodeLookupChildValue(conf, "max-open-files"); if (file_count_str != NULL) { uint32_t file_count = 0; if (ParseSizeStringU32(file_count_str, &file_count) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " "file-store.max-open-files " "from conf file - %s. Killing engine", stream_depth_str); exit(EXIT_FAILURE); } else { if (file_count != 0) { FileSetMaxOpenFiles(file_count); SCLogInfo("file-store will keep a max of %d simultaneously" " open files", file_count); } } } const char *include_pid = ConfNodeLookupChildValue(conf, "include-pid"); if (include_pid != NULL && ConfValIsTrue(include_pid)) { FileIncludePidEnable(); SCLogInfo("enabling pid as a part of all file names"); } StatsRegisterGlobalCounter("file_store.open_files", LogFilestoreOpenFilesCounter); result.ctx = output_ctx; result.ok = true; SCReturnCT(result, "OutputInitResult"); }
int PopulatePickerFromFile( PlaylistPicker* picker, char* fname, const char* basePath, LoopDetectionList *ldList ) { Assert( picker ); Assert( fname ); FILE* weightings = NULL; LoopDetectionListElement* ldElement = NULL; LoopDetectionNode* ldNode = NULL; int lineCount = 0; int pickErr = kPickerPopulateNoErr; char path[kMaxPickerPath]; #if kPartialPathBeginsWithDelimiter if (PathIsAbsolute(fname)) { if ( *basePath ) fname++; #else if ( !PathIsAbsolute(fname) ) { #endif // it's a partial path, expand it to include all // previously traversed paths ::strncpy( path, basePath, kMaxPickerPath-1 ); ::strncat( path, fname, kMaxPickerPath-1 ); } else { // it's an absolute reference. use the path // part of this for the new basePath ::strncpy( path, fname, kMaxPickerPath-1 ); } // path is now either an absolute or working directory // referenced partial path to the playlist file. int len = strlen(path); char lastChar = path[len-1]; if (lastChar == '\n' || lastChar == '\r' || lastChar == ' ') path[len-1] = '\0'; // ldList is passed as NULL by the initial caller. recursive calls // pass along the ldList we create hre if ( ldList == NULL ) ldList = new LoopDetectionList; Assert( ldList ); if ( !ldList ) pickErr = kPickerPopulateNoMem; if ( !pickErr ) { if ( ldList->ForEachUntil( CompareNameToElement, path ) ) { // we're already in the include chain, this is a loop // print a warning (error?) and continue past the loop. //qtss_printf("- Playlists include loop at file: %s\n", path ); pickErr = kPickerPopulateLoopDetected; } } if ( !pickErr ) { ldElement = new LoopDetectionListElement( path ); Assert( ldElement ); if ( ldElement ) { ldNode = new LoopDetectionNode( ldElement ); Assert( ldNode ); if ( !ldNode ) pickErr = kPickerPopulateNoMem; } else pickErr = kPickerPopulateNoMem; } if (::IsDir(path)) return ::PopulatePickerFromDir(picker, path); if ( !pickErr ) { weightings = ::fopen( path, "r" ); if (!weightings) { qtss_printf("- Playlist picker failed opening list file %s\n", path); pickErr = kPickerPopulateFileError; } } if ( !pickErr ) { long lineBuffSize = (kMaxPickerPath *2) - 1; long wordBuffSize = kMaxPickerPath - 1; char lineBuff[kMaxPickerPath * 2]; char wordBuff[kMaxPickerPath]; char* next; char* pathEnd; char* thisLine; // add ourselves to the list ldList->AddNode( ldNode ); // trim off the file name to get just the path part pathEnd = ::strrchr( path, kPathDelimiterChar ); if ( pathEnd ) { pathEnd++; *pathEnd = 0; } else *path = 0; thisLine = lineBuff; if ( ::fgets( lineBuff, lineBuffSize, weightings ) != NULL ) { lineCount++; thisLine = ::TrimLeft( lineBuff ); if ( 0 != ::strncmp(thisLine,"*PLAY-LIST*",11) ) { //qtss_printf("- Playlist file missing *PLAY-LIST* identifier as first line:\n"); //qtss_printf(" %s%s\n", basePath, fname); pickErr = kPickerPopulateBadFormat; } } if ( !pickErr ) { do { next = lineBuff; if ( ::fgets( lineBuff, lineBuffSize, weightings ) == NULL ) break; // qtss_printf("line = %s\n", lineBuff); lineCount++; next = ::TrimLeft( lineBuff ); if ( *next == '#' ) { // it's a comment - just toss //if ( *next ) // qtss_printf( "comment: %s" , &lineBuff[1] ); } else if (*next == '+') // a list { next = ::TrimLeft( next+1 ); // skip past + include if ( *next == '"' ) // get the name from the next part of the buff next = ::GetQuotedWord( wordBuff, next, wordBuffSize ); else next = ::GetWord( wordBuff, next, wordBuffSize ); // recusively populate from the include file. pickErr = PopulatePickerFromFile( picker, wordBuff, path, ldList ); if ( pickErr ) { DisplayPickerErr( pickErr, "Playlist Include failed", fname, lineCount, lineBuff ); pickErr = kPickerPopulateNoErr; } } else if ( *next ) { char numBuff[32]; char expandedFileName[kMaxPickerPath]; int weight = 10; // default weight is 10 // get the movie file name if ( *next == '"' ) next = ::GetQuotedWord( wordBuff, next, wordBuffSize ); else next = ::GetWord( wordBuff, next, wordBuffSize ); if (*wordBuff) { #if kPartialPathBeginsWithDelimiter if ( PathIsAbsolute(wordBuff) ) { char *wordStart = wordBuff; if ( *path ) wordStart++; // full or partial path to the movie ::strcpy( expandedFileName, path ); ::strcat( expandedFileName, wordStart ); } #else if ( !PathIsAbsolute(wordBuff) ) { // it's a partial path.. // cat the path and fname to form the // full or partial path to the movie ::strcpy( expandedFileName, path ); ::strcat( expandedFileName, wordBuff ); } #endif else { // it's an absolute path.. ::strcpy( expandedFileName, wordBuff ); } // then get the weighting ( if supplied ) next = ::GetWord( numBuff, next, 32 ); if ( *numBuff ) weight = ::atoi(numBuff); // qtss_printf("expanded file name = %s\n", expandedFileName); if (::IsDir(expandedFileName)) pickErr = ::PopulatePickerFromDir(picker, expandedFileName, weight); else if ( !picker->AddToList( expandedFileName, weight ) ) pickErr = kPickerPopulateNoMem; } } } while ( feof( weightings ) == 0 && pickErr == kPickerPopulateNoErr ); } // remove ourselves from the list ldList->RemoveNode( ldNode ); } // only report unreported errors. if ( ldList && ldList->GetNumNodes() == 0 && pickErr ) ::DisplayPickerErr( pickErr, "Playlist error", fname, lineCount, NULL ); if ( ldNode ) delete ldNode; // node deletes element else if ( ldElement ) delete ldElement; if ( weightings ) (void)::fclose( weightings ); if ( ldList && ldList->GetNumNodes() == 0 ) { // all done now! delete ldList; ldList = NULL; } return pickErr; } int PopulatePickerFromDir( PlaylistPicker* picker, char* dirPath, int weight ) { static char expandedFileName[kMaxPickerPath]; // static so we don't build up the stack frame on recursion int pickErr = 0; if (dirPath != NULL) strcpy(expandedFileName, dirPath); #ifdef __Win32__ WIN32_FIND_DATA findData; HANDLE findResultHandle; Bool16 keepSearching = true; int len = strlen(expandedFileName); if (expandedFileName[len - 1] != kPathDelimiterChar) { expandedFileName[len] = kPathDelimiterChar; expandedFileName[len+1] = 0; len++; } strcat(expandedFileName, "*"); findResultHandle = ::FindFirstFile( expandedFileName, &findData); if ( NULL == findResultHandle || INVALID_HANDLE_VALUE == findResultHandle ) { //qtss_printf( "FindFirstFile( \"%s\" ): gle = %lu\n", searchPath, GetLastError() ); return 0; } while ( (pickErr == 0) && keepSearching ) { expandedFileName[len] = 0; // retruncate name if (findData.cFileName[0] != '.') // ignore anything beginning with a "." { strcat(expandedFileName, findData.cFileName); if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) pickErr = PopulatePickerFromDir(picker, NULL, weight); else if ( !picker->AddToList( expandedFileName, weight ) ) pickErr = kPickerPopulateNoMem; } keepSearching = FindNextFile( findResultHandle, &findData ); } #else DIR* dir; struct dirent* entry; int len = strlen(expandedFileName); if (expandedFileName[len - 1] != kPathDelimiterChar) { expandedFileName[len] = kPathDelimiterChar; expandedFileName[len+1] = 0; len++; } dir = opendir(expandedFileName); if (dir == NULL) return kPickerPopulateFileError; do { entry = readdir(dir); if (entry == NULL) break; if (entry->d_name[0] == '.') // ignore anything beginning with a "." continue; if (len + strlen(entry->d_name) < kMaxPickerPath) { strcat(expandedFileName, entry->d_name); #if __solaris__ || __sgi__ || __osf__ || __hpux__ if (::IsDir(expandedFileName)) #else if ((entry->d_type & DT_DIR) != 0) #endif pickErr = PopulatePickerFromDir(picker, NULL, weight); else if ( !picker->AddToList( expandedFileName, weight ) ) pickErr = kPickerPopulateNoMem; } expandedFileName[len] = 0; // retruncate name } while (pickErr == 0); //close the directory back up (void)::closedir(dir); #endif return pickErr; }
/** \brief open a generic output "log file", which may be a regular file or a socket * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode * \param rotate Register the file for rotation in HUP. * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate) { char log_path[PATH_MAX]; const char *log_dir; const char *filename, *filetype; // Arg check if (conf == NULL || log_ctx == NULL || default_filename == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " "missing an argument", conf, log_ctx, default_filename); return -1; } if (log_ctx->fp != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric: previously initialized Log CTX " "encountered"); return -1; } // Resolve the given config filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) filename = default_filename; log_dir = ConfigGetLogDirectory(); if (PathIsAbsolute(filename)) { snprintf(log_path, PATH_MAX, "%s", filename); } else { snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } /* Rotate log file based on time */ const char *rotate_int = ConfNodeLookupChildValue(conf, "rotate-interval"); if (rotate_int != NULL) { time_t now = time(NULL); log_ctx->flags |= LOGFILE_ROTATE_INTERVAL; /* Use a specific time */ if (strcmp(rotate_int, "minute") == 0) { log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); log_ctx->rotate_interval = 60; } else if (strcmp(rotate_int, "hour") == 0) { log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); log_ctx->rotate_interval = 3600; } else if (strcmp(rotate_int, "day") == 0) { log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); log_ctx->rotate_interval = 86400; } /* Use a timer */ else { log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int); if (log_ctx->rotate_interval == 0) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "invalid rotate-interval value"); exit(EXIT_FAILURE); } log_ctx->rotate_time = now + log_ctx->rotate_interval; } } filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; const char *filemode = ConfNodeLookupChildValue(conf, "filemode"); uint32_t mode = 0; if (filemode != NULL && ByteExtractStringUint32(&mode, 8, strlen(filemode), filemode) > 0) { log_ctx->filemode = mode; } const char *append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; /* JSON flags */ #ifdef HAVE_LIBJANSSON log_ctx->json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT| JSON_ENSURE_ASCII|JSON_ESCAPE_SLASH; ConfNode *json_flags = ConfNodeLookupChild(conf, "json"); if (json_flags != 0) { const char *preserve_order = ConfNodeLookupChildValue(json_flags, "preserve-order"); if (preserve_order != NULL && ConfValIsFalse(preserve_order)) log_ctx->json_flags &= ~(JSON_PRESERVE_ORDER); const char *compact = ConfNodeLookupChildValue(json_flags, "compact"); if (compact != NULL && ConfValIsFalse(compact)) log_ctx->json_flags &= ~(JSON_COMPACT); const char *ensure_ascii = ConfNodeLookupChildValue(json_flags, "ensure-ascii"); if (ensure_ascii != NULL && ConfValIsFalse(ensure_ascii)) log_ctx->json_flags &= ~(JSON_ENSURE_ASCII); const char *escape_slash = ConfNodeLookupChildValue(json_flags, "escape-slash"); if (escape_slash != NULL && ConfValIsFalse(escape_slash)) log_ctx->json_flags &= ~(JSON_ESCAPE_SLASH); } #endif /* HAVE_LIBJANSSON */ // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { #ifdef BUILD_WITH_UNIXSOCKET /* Don't bail. May be able to connect later. */ log_ctx->is_sock = 1; log_ctx->sock_type = SOCK_STREAM; log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1); #else return -1; #endif } else if (strcasecmp(filetype, "unix_dgram") == 0) { #ifdef BUILD_WITH_UNIXSOCKET /* Don't bail. May be able to connect later. */ log_ctx->is_sock = 1; log_ctx->sock_type = SOCK_DGRAM; log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); #else return -1; #endif } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || strcasecmp(filetype, "file") == 0) { log_ctx->fp = SCLogOpenFileFp(log_path, append, log_ctx->filemode); if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine log_ctx->is_regular = 1; if (rotate) { OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); } } else if (strcasecmp(filetype, "pcie") == 0) { log_ctx->pcie_fp = SCLogOpenPcieFp(log_ctx, log_path, append); if (log_ctx->pcie_fp == NULL) return -1; // Error already logged by Open...Fp routine #ifdef HAVE_LIBHIREDIS } else if (strcasecmp(filetype, "redis") == 0) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); if (SCConfLogOpenRedis(redis_node, log_ctx) < 0) { SCLogError(SC_ERR_REDIS, "failed to open redis output"); return -1; } log_ctx->type = LOGFILE_TYPE_REDIS; #endif } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.filetype. Expected \"regular\" (default), \"unix_stream\", " "\"pcie\" " "or \"unix_dgram\"", conf->name); } log_ctx->filename = SCStrdup(log_path); if (unlikely(log_ctx->filename == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for filename"); return -1; } #ifdef BUILD_WITH_UNIXSOCKET /* If a socket and running live, do non-blocking writes. */ if (log_ctx->is_sock && run_mode_offline == 0) { SCLogInfo("Setting logging socket of non-blocking in live mode."); log_ctx->send_flags |= MSG_DONTWAIT; } #endif SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); return 0; }