Files in directory with wildcard on Windows - c++

how can I easy get all files paths from path containing a wildcards? For example: C:/Data*Set/Files*/*.txt and I wrote it on Linux using glob function but I can't do it on Windows :/
FindFirstFile unfortunately doesn't support wildcards in directory names.
I think there should be a Windows solution available but I can't find it.

So you should do away with using OS specific file access, in favor of the OS independent: Filesystem Library
Let's say that you're given filesystem::path input which contains the path with wildcards. To use this to solve your problem you'd need to:
Use parent_path to break apart input into directories
Use filename to obtain the input filename
Obtain a directory_iterator to the relative or absolute path where the input begins
Create a recursive function which takes in begin and end iterators to the obtained parent path, the directory iterator, and the filename
Any time a directory or filename uses a '*' use a regex with the iterator to determine the directory which should be progressed to next
Either return the path to the matching file or an empty path
Due to the excellent Ben Voigt's comment I've updated the algorithm to step over unwildcarded directories.
For example:
regex GenerateRegex(string& arg) {
for (auto i = arg.find('*'); i != string::npos; i = arg.find('*', i + 2)) {
arg.insert(i, 1, '.');
}
return regex(arg);
}
filesystem::path FindFirstFile(filesystem::path directory, filesystem::path::const_iterator& start, const filesystem::path::const_iterator& finish, string& filename) {
while (start != finish && start->string().find('*') == string::npos) {
directory /= *start++;
}
filesystem::directory_iterator it(directory);
filesystem::path result;
if (it != filesystem::directory_iterator()) {
if (start == finish) {
for (auto i = filename.find('.'); i != string::npos; i = filename.find('.', i + 2)) {
filename.insert(i, 1, '\\');
}
const auto re = GenerateRegex(filename);
do {
if (!filesystem::is_directory(it->status()) && regex_match(it->path().string(), re)) {
result = *it;
break;
}
} while (++it != filesystem::directory_iterator());
}
else {
const auto re = GenerateRegex(start->string());
do {
if (it->is_directory() && regex_match(prev(it->path().end())->string(), re)) {
result = FindFirstFile(it->path(), next(start), finish, filename);
if (!result.empty()) {
break;
}
}
} while (++it != filesystem::directory_iterator());
}
}
return result;
}
Which can be called with:
const filesystem::path input("C:/Test/Data*Set/Files*/*.txt");
if (input.is_absolute()) {
const auto relative_parent = input.parent_path().relative_path();
cout << FindFirstFile(input.root_path(), begin(relative_parent), end(relative_parent), input.filename().string()) << endl;
} else {
const auto parent = input.parent_path();
cout << FindFirstFile(filesystem::current_path(), begin(parent), end(parent), input.filename().string()) << endl;
}
Live Example

need understand how FindFirstFile[Ex] work. this is shell over NtQueryDirectoryFile. FindFirstFile[Ex] need divide input name to folder name (which will be opened in used as FileHandle) and search mask used as FileName. mask can be only in file name. folder must have exact name without wildcard to opened first.
as result FindFirstFile[Ex] always open concrete single folder and search in this folder by mask. for recursive search files - we need recursive call FindFirstFile[Ex]. simply usual we use the same constant search mask on all levels. for example when we want find all files begin from X:\SomeFolder we first call FindFirstFile[Ex] with X:\SomeFolder\* on level 0. if we found SomeSubfolder - we call FindFirstFile[Ex] with X:\SomeFolder\SomeSubfolder\* on level 1 and so on. but we can use different search masks on different levels. Data*Set on level 0, Files* on level 1, *.txt on level 2
so we need call FindFirstFileEx recursive and on different recursions level use different masks. for example we want found c:\Program*\*\*.txt. we need start from c:\Program*, then for every founded result append \* mask, then append \*.txt on next level. or we can for example want next - search files by next mask - c:\Program Files*\Internet Explorer\* with any deep level. we can use constant deep search folder mask (optional) with final mask (also optional) used already on all more deep levels.
all this can be really not so hard and efficient implemented:
struct ENUM_CONTEXT : WIN32_FIND_DATA
{
PCWSTR _szMask;
PCWSTR *_pszMask;
ULONG _MaskCount;
ULONG _MaxLevel;
ULONG _nFiles;
ULONG _nFolders;
WCHAR _FileName[MAXSHORT + 1];
void StartEnum(PCWSTR pcszRoot, PCWSTR pszMask[], ULONG MaskCount, PCWSTR szMask, ULONG MaxLevel, PSTR prefix)
{
SIZE_T len = wcslen(pcszRoot);
if (len < RTL_NUMBER_OF(_FileName))
{
memcpy(_FileName, pcszRoot, len * sizeof(WCHAR));
_szMask = szMask, _pszMask = pszMask, _MaskCount = MaskCount;
_MaxLevel = szMask ? MaxLevel : MaskCount;
_nFolders = 0, _nFolders = 0;
Enum(_FileName + len, 0, prefix);
}
}
void Enum(PWSTR pszEnd, ULONG nLevel, PSTR prefix);
};
void ENUM_CONTEXT::Enum(PWSTR pszEnd, ULONG nLevel, PSTR prefix)
{
if (nLevel > _MaxLevel)
{
return ;
}
PCWSTR lpFileName = _FileName;
SIZE_T cb = lpFileName + RTL_NUMBER_OF(_FileName) - pszEnd;
PCWSTR szMask = nLevel < _MaskCount ? _pszMask[nLevel] : _szMask;
SIZE_T cchMask = wcslen(szMask) + 1;
if (cb < cchMask + 1)
{
return ;
}
*pszEnd++ = L'\\', cb--;
DbgPrint("%s[<%.*S>]\n", prefix, pszEnd - lpFileName, lpFileName);
memcpy(pszEnd, szMask, cchMask * sizeof(WCHAR));
ULONG dwError;
HANDLE hFindFile = FindFirstFileEx(lpFileName, FindExInfoBasic, this, FindExSearchNameMatch, 0, FIND_FIRST_EX_LARGE_FETCH);
if (hFindFile != INVALID_HANDLE_VALUE)
{
PWSTR FileName = cFileName;
do
{
SIZE_T FileNameLength = wcslen(FileName);
switch (FileNameLength)
{
case 2:
if (FileName[1] != '.') break;
case 1:
if (FileName[0] == '.') continue;
}
if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_nFolders++;
if (!(dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
{
if (cb < FileNameLength)
{
__debugbreak();
}
else
{
memcpy(pszEnd, FileName, FileNameLength * sizeof(WCHAR));
Enum(pszEnd + FileNameLength, nLevel + 1, prefix - 1);
}
}
}
else if (nLevel >= _MaskCount || (!_szMask && nLevel == _MaskCount - 1))
{
_nFiles++;
DbgPrint("%s%u%u <%.*S>\n", prefix, nFileSizeLow, nFileSizeHigh, FileNameLength, FileName);
}
} while (FindNextFile(hFindFile, this));
if ((dwError = GetLastError()) == ERROR_NO_MORE_FILES)
{
dwError = NOERROR;
}
FindClose(hFindFile);
}
else
{
dwError = GetLastError();
}
if (dwError && dwError != ERROR_FILE_NOT_FOUND)
{
DbgPrint("%s[<%.*S>] err = %u\n", prefix, pszEnd - lpFileName, lpFileName, dwError);
}
}
void Test(PCWSTR pcszRoot)
{
char prefix[MAXUCHAR + 1];
memset(prefix, '\t', RTL_NUMBER_OF(prefix) - 1);
prefix[RTL_NUMBER_OF(prefix) - 1] = 0;
ENUM_CONTEXT ectx;
static PCWSTR Masks[] = { L"Program*", L"*", L"*.txt" };
static PCWSTR Masks2[] = { L"Program*", L"*" };
static PCWSTR Masks3[] = { L"Program Files*", L"Internet Explorer" };
// search Program*\*\*.txt with fixed deep level
ectx.StartEnum(pcszRoot, Masks, RTL_NUMBER_OF(Masks), 0, RTL_NUMBER_OF(prefix) - 1, prefix + RTL_NUMBER_OF(prefix) - 1);
// search *.txt files from Program*\*\ - any deep level
ectx.StartEnum(pcszRoot, Masks2, RTL_NUMBER_OF(Masks2), L"*.txt", RTL_NUMBER_OF(prefix) - 1, prefix + RTL_NUMBER_OF(prefix) - 1);
// search all files (*) from Program Files*\Internet Explorer\
ectx.StartEnum(pcszRoot, Masks3, RTL_NUMBER_OF(Masks3), L"*", RTL_NUMBER_OF(prefix) - 1, prefix + RTL_NUMBER_OF(prefix) - 1);
}

Related

Iterate directory or files with wildcards in c++ [duplicate]

how can I easy get all files paths from path containing a wildcards? For example: C:/Data*Set/Files*/*.txt and I wrote it on Linux using glob function but I can't do it on Windows :/
FindFirstFile unfortunately doesn't support wildcards in directory names.
I think there should be a Windows solution available but I can't find it.
So you should do away with using OS specific file access, in favor of the OS independent: Filesystem Library
Let's say that you're given filesystem::path input which contains the path with wildcards. To use this to solve your problem you'd need to:
Use parent_path to break apart input into directories
Use filename to obtain the input filename
Obtain a directory_iterator to the relative or absolute path where the input begins
Create a recursive function which takes in begin and end iterators to the obtained parent path, the directory iterator, and the filename
Any time a directory or filename uses a '*' use a regex with the iterator to determine the directory which should be progressed to next
Either return the path to the matching file or an empty path
Due to the excellent Ben Voigt's comment I've updated the algorithm to step over unwildcarded directories.
For example:
regex GenerateRegex(string& arg) {
for (auto i = arg.find('*'); i != string::npos; i = arg.find('*', i + 2)) {
arg.insert(i, 1, '.');
}
return regex(arg);
}
filesystem::path FindFirstFile(filesystem::path directory, filesystem::path::const_iterator& start, const filesystem::path::const_iterator& finish, string& filename) {
while (start != finish && start->string().find('*') == string::npos) {
directory /= *start++;
}
filesystem::directory_iterator it(directory);
filesystem::path result;
if (it != filesystem::directory_iterator()) {
if (start == finish) {
for (auto i = filename.find('.'); i != string::npos; i = filename.find('.', i + 2)) {
filename.insert(i, 1, '\\');
}
const auto re = GenerateRegex(filename);
do {
if (!filesystem::is_directory(it->status()) && regex_match(it->path().string(), re)) {
result = *it;
break;
}
} while (++it != filesystem::directory_iterator());
}
else {
const auto re = GenerateRegex(start->string());
do {
if (it->is_directory() && regex_match(prev(it->path().end())->string(), re)) {
result = FindFirstFile(it->path(), next(start), finish, filename);
if (!result.empty()) {
break;
}
}
} while (++it != filesystem::directory_iterator());
}
}
return result;
}
Which can be called with:
const filesystem::path input("C:/Test/Data*Set/Files*/*.txt");
if (input.is_absolute()) {
const auto relative_parent = input.parent_path().relative_path();
cout << FindFirstFile(input.root_path(), begin(relative_parent), end(relative_parent), input.filename().string()) << endl;
} else {
const auto parent = input.parent_path();
cout << FindFirstFile(filesystem::current_path(), begin(parent), end(parent), input.filename().string()) << endl;
}
Live Example
need understand how FindFirstFile[Ex] work. this is shell over NtQueryDirectoryFile. FindFirstFile[Ex] need divide input name to folder name (which will be opened in used as FileHandle) and search mask used as FileName. mask can be only in file name. folder must have exact name without wildcard to opened first.
as result FindFirstFile[Ex] always open concrete single folder and search in this folder by mask. for recursive search files - we need recursive call FindFirstFile[Ex]. simply usual we use the same constant search mask on all levels. for example when we want find all files begin from X:\SomeFolder we first call FindFirstFile[Ex] with X:\SomeFolder\* on level 0. if we found SomeSubfolder - we call FindFirstFile[Ex] with X:\SomeFolder\SomeSubfolder\* on level 1 and so on. but we can use different search masks on different levels. Data*Set on level 0, Files* on level 1, *.txt on level 2
so we need call FindFirstFileEx recursive and on different recursions level use different masks. for example we want found c:\Program*\*\*.txt. we need start from c:\Program*, then for every founded result append \* mask, then append \*.txt on next level. or we can for example want next - search files by next mask - c:\Program Files*\Internet Explorer\* with any deep level. we can use constant deep search folder mask (optional) with final mask (also optional) used already on all more deep levels.
all this can be really not so hard and efficient implemented:
struct ENUM_CONTEXT : WIN32_FIND_DATA
{
PCWSTR _szMask;
PCWSTR *_pszMask;
ULONG _MaskCount;
ULONG _MaxLevel;
ULONG _nFiles;
ULONG _nFolders;
WCHAR _FileName[MAXSHORT + 1];
void StartEnum(PCWSTR pcszRoot, PCWSTR pszMask[], ULONG MaskCount, PCWSTR szMask, ULONG MaxLevel, PSTR prefix)
{
SIZE_T len = wcslen(pcszRoot);
if (len < RTL_NUMBER_OF(_FileName))
{
memcpy(_FileName, pcszRoot, len * sizeof(WCHAR));
_szMask = szMask, _pszMask = pszMask, _MaskCount = MaskCount;
_MaxLevel = szMask ? MaxLevel : MaskCount;
_nFolders = 0, _nFolders = 0;
Enum(_FileName + len, 0, prefix);
}
}
void Enum(PWSTR pszEnd, ULONG nLevel, PSTR prefix);
};
void ENUM_CONTEXT::Enum(PWSTR pszEnd, ULONG nLevel, PSTR prefix)
{
if (nLevel > _MaxLevel)
{
return ;
}
PCWSTR lpFileName = _FileName;
SIZE_T cb = lpFileName + RTL_NUMBER_OF(_FileName) - pszEnd;
PCWSTR szMask = nLevel < _MaskCount ? _pszMask[nLevel] : _szMask;
SIZE_T cchMask = wcslen(szMask) + 1;
if (cb < cchMask + 1)
{
return ;
}
*pszEnd++ = L'\\', cb--;
DbgPrint("%s[<%.*S>]\n", prefix, pszEnd - lpFileName, lpFileName);
memcpy(pszEnd, szMask, cchMask * sizeof(WCHAR));
ULONG dwError;
HANDLE hFindFile = FindFirstFileEx(lpFileName, FindExInfoBasic, this, FindExSearchNameMatch, 0, FIND_FIRST_EX_LARGE_FETCH);
if (hFindFile != INVALID_HANDLE_VALUE)
{
PWSTR FileName = cFileName;
do
{
SIZE_T FileNameLength = wcslen(FileName);
switch (FileNameLength)
{
case 2:
if (FileName[1] != '.') break;
case 1:
if (FileName[0] == '.') continue;
}
if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_nFolders++;
if (!(dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
{
if (cb < FileNameLength)
{
__debugbreak();
}
else
{
memcpy(pszEnd, FileName, FileNameLength * sizeof(WCHAR));
Enum(pszEnd + FileNameLength, nLevel + 1, prefix - 1);
}
}
}
else if (nLevel >= _MaskCount || (!_szMask && nLevel == _MaskCount - 1))
{
_nFiles++;
DbgPrint("%s%u%u <%.*S>\n", prefix, nFileSizeLow, nFileSizeHigh, FileNameLength, FileName);
}
} while (FindNextFile(hFindFile, this));
if ((dwError = GetLastError()) == ERROR_NO_MORE_FILES)
{
dwError = NOERROR;
}
FindClose(hFindFile);
}
else
{
dwError = GetLastError();
}
if (dwError && dwError != ERROR_FILE_NOT_FOUND)
{
DbgPrint("%s[<%.*S>] err = %u\n", prefix, pszEnd - lpFileName, lpFileName, dwError);
}
}
void Test(PCWSTR pcszRoot)
{
char prefix[MAXUCHAR + 1];
memset(prefix, '\t', RTL_NUMBER_OF(prefix) - 1);
prefix[RTL_NUMBER_OF(prefix) - 1] = 0;
ENUM_CONTEXT ectx;
static PCWSTR Masks[] = { L"Program*", L"*", L"*.txt" };
static PCWSTR Masks2[] = { L"Program*", L"*" };
static PCWSTR Masks3[] = { L"Program Files*", L"Internet Explorer" };
// search Program*\*\*.txt with fixed deep level
ectx.StartEnum(pcszRoot, Masks, RTL_NUMBER_OF(Masks), 0, RTL_NUMBER_OF(prefix) - 1, prefix + RTL_NUMBER_OF(prefix) - 1);
// search *.txt files from Program*\*\ - any deep level
ectx.StartEnum(pcszRoot, Masks2, RTL_NUMBER_OF(Masks2), L"*.txt", RTL_NUMBER_OF(prefix) - 1, prefix + RTL_NUMBER_OF(prefix) - 1);
// search all files (*) from Program Files*\Internet Explorer\
ectx.StartEnum(pcszRoot, Masks3, RTL_NUMBER_OF(Masks3), L"*", RTL_NUMBER_OF(prefix) - 1, prefix + RTL_NUMBER_OF(prefix) - 1);
}

How to look up 64-bit module's function table when it's mapped in memory?

My goal is to understand stack unwinding in 64-bit PE32+ executable format in Windows, or how the following API can calculate addresses of a function prologue, body, epilogue, etc.:
CONTEXT context = {0};
RtlCaptureContext(&context);
DWORD64 ImgBase = 0;
RUNTIME_FUNCTION* pRTFn = RtlLookupFunctionEntry(context.Rip, &ImgBase, NULL);
_tprintf(L"Prologue=0x%p\n", (void*)(ImgBase + pRTFn->BeginAddress));
I know that the information on the offsets of all non-leaf functions used by the linker is included in the PE32+ header in the exceptions directory. So I tried to write my own function to parse it. I got to this point where I got stumped:
//INFO -- must be compiled as x64 only!
void GetFunctionTable(BYTE* lpBaseAddress, size_t szImageSz)
{
if(lpBaseAddress)
{
if(szImageSz > sizeof(IMAGE_DOS_HEADER))
{
IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)lpBaseAddress;
if(pDOSHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS* pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY pDataDirectories = NULL;
if(pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
//64-bit image only
IMAGE_NT_HEADERS64* pHdr64 = (IMAGE_NT_HEADERS64*)pNtHeader;
IMAGE_OPTIONAL_HEADER64* pIOH64 = &pHdr64->OptionalHeader;
pDataDirectories = pIOH64->DataDirectory;
IMAGE_DATA_DIRECTORY* pExceptDir = &pDataDirectories[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
if(pExceptDir->VirtualAddress &&
pExceptDir->Size)
{
IMAGE_RUNTIME_FUNCTION_ENTRY* pRFs = (IMAGE_RUNTIME_FUNCTION_ENTRY*)
GetPtrFromRVA64(pExceptDir->VirtualAddress, pNtHeader, lpBaseAddress);
//'pRFs' = should point to an array of RUNTIME_FUNCTION structs
// but in my case it points to an empty region of memory with all zeros.
}
}
}
}
}
}
with the following helper functions:
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader64(DWORD_PTR rva, PIMAGE_NT_HEADERS64 pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned int i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}
LPVOID GetPtrFromRVA64(DWORD rva, const void* pNTHeader, const void* imageBase)
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT_PTR delta;
pSectionHdr = GetEnclosingSectionHeader64( rva, (PIMAGE_NT_HEADERS64)pNTHeader );
if ( !pSectionHdr )
return 0;
delta = (INT_PTR)(pSectionHdr->VirtualAddress - pSectionHdr->PointerToRawData);
return (PVOID) ( (BYTE*)imageBase + rva - delta );
}
So I'm testing it on the self executable:
HMODULE hMod = ::GetModuleHandle(NULL);
MODULEINFO mi = {0};
if(::GetModuleInformation(::GetCurrentProcess(), hMod, &mi, sizeof(mi)))
{
GetFunctionTable((BYTE*)hMod, mi.SizeOfImage);
}
But the problem is that inside my GetFunctionTable when I try to look up the function table mapped in memory in the IMAGE_DIRECTORY_ENTRY_EXCEPTION directory, I'm getting a pointer (i.e. IMAGE_RUNTIME_FUNCTION_ENTRY*) to an empty region of memory. I must be not translating the rva address correctly.
So anyone who knows how PE32+ header is mapped in memory, can please show what am I doing wrong there?

Reading Subdirectories with win32

I'm trying to read some sub-directories with win32 functions and it looks like this. Most everything works fine. I haven't got to run the function completely because I'm still debugging it. My problem: I have 5 actual files and two sub-directories. When I try to grab the file names of each subdirectory and file in the directory I get this: ".", "..", "Subdirectory1", "Subdirectory", "rest of the files"... Why did I get a period, two periods, and then the actual files in the folder?
static std::vector<std::string> ReadAllFilesIntoArray(std::string contentDirPath, std::string fileType)
{
std::vector<std::string> filePaths;
std::wstring strTemp;
strTemp.assign(contentDirPath.begin(), contentDirPath.end());
HANDLE hFile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA FindFileData;
hFile = FindFirstFile(strTemp.c_str(), &FindFileData);
if (INVALID_HANDLE_VALUE != hFile)
{
int i = 0;
do{
// If it's a directory
if (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes)
{
// Convert wchar[260] -> std::string
char ch[260];
char DefChar = ' ';
WideCharToMultiByte(CP_ACP, 0, FindFileData.cFileName, -1, ch, 260, &DefChar, NULL);
std::string ss(ch);
std::vector<std::string> localFilePaths = ReadAllFilesIntoArray(contentDirPath.assign(contentDirPath.begin(), contentDirPath.end() - 5) + ss + "//*", fileType);
// Append the file paths found in the subdirectory to the ones found in the current directory
filePaths.insert(filePaths.begin(), localFilePaths.begin(), localFilePaths.end());
}
// Convert wchar[260] -> std::string
char ch[260];
char DefChar = ' ';
WideCharToMultiByte(CP_ACP, 0, FindFileData.cFileName, -1, ch, 260, &DefChar, NULL);
std::string tempString(ch);
// Then add to list if it's equal to the file type we are checking for
if (tempString.substr(tempString.size() - 3, tempString.size()) == fileType)
{
filePaths.resize(i + 1);
filePaths[i] = ch;
i++;
}
} while (FindNextFile(hFile, &FindFileData));
FindClose(hFile);
}
return filePaths;
}
They are special names that represent the current directory (.) and the parent directory (..). Enumeration code is typically written with special case checks to ignore these two special values.

Not able to add certificate policy extension using openssl APIs in c++

I tried using following syntax for the same :
add_ext(x509OutCertificate, NID_certificate_policies, "Policy: 2.16.840.1.113733.1.7.54 ,CPS: https://www.verisign.com/cps");
add_ext(x509OutCertificate, NID_certificate_policies, "2.16.840.1.113733.1.7.54,https://www.verisign.com/cps");
& many more combinations.
but not able to add this extension in certificate. Any clue what is wrong?
Thanks in advance
This is really a comment, but the comment does not have the space.
$ grep -R NID_certificate_policies *crypto/objects/obj_dat.h: NID_certificate_policies,3,&(lvalues[512]),0},
crypto/objects/objects.h:#define NID_certificate_policies 89
crypto/objects/obj_mac.h:#define NID_certificate_policies 89
crypto/x509v3/v3_cpols.c:NID_certificate_policies, 0,ASN1_ITEM_ref(CERTIFICATEPOLICIES),
crypto/x509v3/pcy_cache.c: ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL);
crypto/x509v3/v3_purp.c: NID_certificate_policies, /* 89 */
Looking at v3_cpols.c, there's an ominous warning:
/* Certificate policies extension support: this one is a bit complex... */
Here's how its declared:
const X509V3_EXT_METHOD v3_cpols = {
NID_certificate_policies, 0,ASN1_ITEM_ref(CERTIFICATEPOLICIES),
0,0,0,0,
0,0,
0,0,
(X509V3_EXT_I2R)i2r_certpol,
(X509V3_EXT_R2I)r2i_certpol,
NULL
};
ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO)
ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES)
IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
v3_cpol is then used in ext_dat.h:
static const X509V3_EXT_METHOD *standard_exts[] = {
&v3_nscert,
&v3_ns_ia5_list[0],
&v3_ns_ia5_list[1],
&v3_ns_ia5_list[2],
&v3_ns_ia5_list[3],
&v3_ns_ia5_list[4],
&v3_ns_ia5_list[5],
&v3_ns_ia5_list[6],
...
&v3_cpols,
...
};
There does not appear to be documentation or clear usage. The two books I have on OpenSSL lack a treatment on it. It looks like you are in muddy waters.
Perhaps the folks at the OpenSSL user's list can help out. I suggest it because some folks on the list can probably answer it (SH, DT, VD, etc), but I have not seen them on Stack Overflow's site.
Its been a long time for this question, but i looked into openssl1.0.2k source code, and i found its not support add cps extension directly:
static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, char *value)
{
WriteLogToFile("In r2i_certpol");
STACK_OF(POLICYINFO) *pols = NULL;
char *pstr;
POLICYINFO *pol;
ASN1_OBJECT *pobj;
STACK_OF(CONF_VALUE) *vals;
CONF_VALUE *cnf;
int i, ia5org;
pols = sk_POLICYINFO_new_null();
if (pols == NULL) {
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
return NULL;
}
WriteLogToFile("Before X509V3_parse_list");
vals = X509V3_parse_list(value);
WriteLogToFile("After X509V3_parse_list");
if (vals == NULL) {
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_X509V3_LIB);
goto err;
}
ia5org = 0;
for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
cnf = sk_CONF_VALUE_value(vals, i);
if (cnf->value || !cnf->name) {
char str[1000];
sprintf(str, "cnf->value: %s, cnf->name: %s", cnf->value, cnf->name);
WriteLogToFile(str);
X509V3err(X509V3_F_R2I_CERTPOL,
X509V3_R_INVALID_POLICY_IDENTIFIER);
X509V3_conf_err(cnf);
goto err;
}
pstr = cnf->name;
WriteLogToFile(pstr);
if (!strcmp(pstr, "ia5org")) {
ia5org = 1;
continue;
} else if (*pstr == '#') {
STACK_OF(CONF_VALUE) *polsect;
polsect = X509V3_get_section(ctx, pstr + 1);
if (!polsect) {
X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_SECTION);
X509V3_conf_err(cnf);
goto err;
}
pol = policy_section(ctx, polsect, ia5org);
X509V3_section_free(ctx, polsect);
if (!pol)
goto err;
} else {
if (!(pobj = OBJ_txt2obj(cnf->name, 0))) {
X509V3err(X509V3_F_R2I_CERTPOL,
X509V3_R_INVALID_OBJECT_IDENTIFIER);
X509V3_conf_err(cnf);
goto err;
}
pol = POLICYINFO_new();
if (pol == NULL) {
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
goto err;
}
pol->policyid = pobj;
}
if (!sk_POLICYINFO_push(pols, pol)) {
POLICYINFO_free(pol);
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
return pols;
err:
sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
return NULL;
}
The "CPS" has to be in section part, which is configured by openssl.conf file, so anyone met this problem has to put cps in that configure file, and tell openssl to search that part, like the code below:
bool AddX509ExtensionFromFile(X509* cert, X509* issuer, int nid, char* value,char* extFile)
{
if (extFile)
{
long errorline = -1;
X509V3_CTX ctx2;
CONF* extconf = NCONF_new(NULL);
if (!NCONF_load(extconf, extFile, &errorline))
{
if (errorline <= 0)
{
printf("NCONF_load error\n");
}
else
{
printf("error on line %ld of config file '%s'\n", errorline, extFile);
}
}
char* extsect = "default";
X509V3_set_ctx_test(&ctx2);
X509V3_set_nconf(&ctx2, extconf);
if (!X509V3_EXT_add_nconf(extconf, &ctx2, extsect, NULL))
{
printf("error loading extension section %s\n", extsect);
}
X509V3_set_ctx(&ctx2, issuer, cert, NULL, NULL, 0);
X509_EXTENSION* ex = X509V3_EXT_conf_nid(NULL, &ctx2, nid, value);
if (!ex) {
return false;
}
int result = X509_add_ext(cert, ex, -1);
X509_EXTENSION_free(ex);
return (result == 0) ? true : false;
}
return false;
}

count the number of directories in a folder C++ windows

I have written a Java program that at one point counts the number of folders in a directory. I would like to translate this program into C++ (I'm trying to learn it). I've been able to translate most of the program, but I haven't been able to find a way to count the subdirectories of a directory. How would I accomplish this?
Thanks in advance
Here is an implementation using the Win32 API.
SubdirCount takes a directory path string argument and it returns a count of its immediate child subdirectories (as an int). Hidden subdirectories are included, but any named "." or ".." are not counted.
FindFirstFile is a TCHAR-taking alias which ends up as either FindFirstFileA or FindFirstFileW. In order to keep strings TCHAR, without assuming availabilty of CString, the example here includes some awkward code just for appending "/*" to the function's argument.
#include <tchar.h>
#include <windows.h>
int SubdirCount(const TCHAR* parent_path) {
// The hideous string manipulation code below
// prepares a TCHAR wildcard string (sub_wild)
// matching any subdirectory immediately under
// parent_path by appending "\*"
size_t len = _tcslen(parent_path);
const size_t alloc_len = len + 3;
TCHAR* sub_wild = new TCHAR[alloc_len];
_tcscpy_s(sub_wild, alloc_len, parent_path);
if(len && sub_wild[len-1] != _T('\\')) { sub_wild[len++] = _T('\\'); }
sub_wild[len++] = _T('*');
sub_wild[len++] = _T('\0');
// File enumeration starts here
WIN32_FIND_DATA fd;
HANDLE hfind;
int count = 0;
if(INVALID_HANDLE_VALUE != (hfind = FindFirstFile(sub_wild, &fd))) {
do {
if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// is_alias_dir is true if directory name is "." or ".."
const bool is_alias_dir = fd.cFileName[0] == _T('.') &&
(!fd.cFileName[1] || (fd.cFileName[1] == _T('.') &&
!fd.cFileName[2]));
count += !is_alias_dir;
}
} while(FindNextFile(hfind, &fd));
FindClose(hfind);
}
delete [] sub_wild;
return count;
}