How do I use Minizip (on Zlib)? - c

I'm trying to archive files for a cross-platform application, and it looks like Minizip (built on zlib) is about as portable as archivers come.
When I try to run the following dummy code, however, I get a system error [my executable] has stopped working. Windows can check online for a solution to the problem.
Can anyone help me see how to use this library? — (there's no doc or tutorial anywhere that I can find)
zip_fileinfo zfi;
int main()
{
zipFile zf = zipOpen("myarch.zip",APPEND_STATUS_ADDINZIP);
int ret = zipOpenNewFileInZip(zf,
"myfile.txt",
&zfi,
NULL, 0,
NULL, 0,
"my comment for this interior file",
Z_DEFLATED,
Z_NO_COMPRESSION
);
zipCloseFileInZip(zf);
zipClose(zf, "my comment for exterior file");
return 0;
}
Specs: Msys + MinGW, Windows 7, using zlibwapi.dll from zlib125dll.zip/dll32

Since I found this question via Google and it didn't contain any complete, working code, I am providing some here for future visitors.
int CreateZipFile (std::vector<wstring> paths)
{
zipFile zf = zipOpen(std::string(destinationPath.begin(), destinationPath.end()).c_str(), APPEND_STATUS_CREATE);
if (zf == NULL)
return 1;
bool _return = true;
for (size_t i = 0; i < paths.size(); i++)
{
std::fstream file(paths[i].c_str(), std::ios::binary | std::ios::in);
if (file.is_open())
{
file.seekg(0, std::ios::end);
long size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
if (size == 0 || file.read(&buffer[0], size))
{
zip_fileinfo zfi = { 0 };
std::wstring fileName = paths[i].substr(paths[i].rfind('\\')+1);
if (S_OK == zipOpenNewFileInZip(zf, std::string(fileName.begin(), fileName.end()).c_str(), &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION))
{
if (zipWriteInFileInZip(zf, size == 0 ? "" : &buffer[0], size))
_return = false;
if (zipCloseFileInZip(zf))
_return = false;
file.close();
continue;
}
}
file.close();
}
_return = false;
}
if (zipClose(zf, NULL))
return 3;
if (!_return)
return 4;
return S_OK;
}

The minizip library does come with examples; minizip.c for zipping and miniunz.c for unzipping. Both are command line utilities that show how to use the library. They are a mess though.
You also need to fill the zfi zip_fileinfo. At the very least you should initialize the structure to zero. zfi contains information about the file you want to store using zipOpenNewFileInZip. The structure should contain the date and attributes of "myfile.txt".
I recommend using PKWARE Desktop to diagnosis zip issues. It shows the structure/properties of the files in the ZIP and the ZIP file itself. When I opened the myarch.zip it told me there were errors. I drilled down into the file properties and found that the attributes were off.

The minizip lib is well documented. Just open the zip.h for details.
I can tell you here, you may have passed a wrong parameter for zipOpen. (APPEND_STATUS_ADDINZIP requires an existing zip file!)
Also, please check whether zipOpen returns a valid zipFile handle.

Related

Open unsupported file type extensions with uwp app

This is a PR for an uwp text editor app where I am implementing desktop extension to give user choice of opening file for which association not declared in manifest. User can choose to open the file with the extension which then launches the file with the uwp app. However I am having following issues:
The StorageFile.GetFileFromPathAsync() doesn't work for hidden files. Trying to handle file activation using this article gives following error:
System.Exception HResult=0xD0000225 Message=The text associated with
this error code could not be found.
The text associated with this error code could not be found.
Source=Windows.ApplicationModel StackTrace: at
Windows.ApplicationModel.AppInstance.GetActivatedEventArgs()
Also launching with Launcher.LaunchFileAsync() doesn't work for unsupported extensions.
Any help regarding these issues??
In Windows 10 2004 (build 19041) microsoft introduced uap10:FileType attribute in package manifest and by providing * as the value the app is available in open with menu of all types of files even files without any extension. To use this just add the following code to your manifest:
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
...
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="anyfile">
<uap:Logo>Assets\mylogo.png</uap:Logo>
<uap:SupportedFileTypes>
<uap:FileType>.txt</uap:FileType>
<uap10:FileType>*</uap10:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
This only works for Windows 10 build 19041 and above. The additional uap:FileType is necessary if app targets minimum version below 19041 to pass manifest validation, otherwise it can be omitted.
Update 1
For Windows 10 version older than build 19041, a desktop component can be provided that uses IApplicationActivationManager::ActivateForFile to redirect file activation to UWP app. The sample code in C++/WinRT looks like this:
init_apartment();
LPWSTR* szArglist = NULL;
INT nArgs;
szArglist = CommandLineToArgvW(GetCommandLine(), &nArgs);
if (szArglist && nArgs > 1)
{
INT ct = nArgs - 1;
HRESULT hr = E_OUTOFMEMORY;
com_ptr<IShellItemArray> ppsia = NULL;
PIDLIST_ABSOLUTE* rgpidl = new(std::nothrow) PIDLIST_ABSOLUTE[ct];
if (rgpidl)
{
hr = S_OK;
INT cpidl;
for (cpidl = 0; SUCCEEDED(hr) && cpidl < ct; cpidl++)
{
hr = SHParseDisplayName(szArglist[cpidl + 1], NULL, &rgpidl[cpidl], 0, NULL);
}
if (cpidl > 0 && SUCCEEDED(SHCreateShellItemArrayFromIDLists(cpidl, rgpidl, ppsia.put())))
{
com_ptr<IApplicationActivationManager> appActivationMgr = NULL;
if (SUCCEEDED(CoCreateInstance(CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER, __uuidof(appActivationMgr), appActivationMgr.put_void())))
{
DWORD pid = 0;
appActivationMgr->ActivateForFile(AUMID, ppsia.get(), NULL, &pid);
}
appActivationMgr.~com_ptr();
}
for (INT i = 0; i < cpidl; i++)
{
CoTaskMemFree(rgpidl[i]);
}
}
ppsia.~com_ptr();
delete[] rgpidl;
}
LocalFree(szArglist);
uninit_apartment();
Additional advantage of using above method to redirect activation is user can even open restricted file types (i.e. .cmd, .bat etc) with UWP app directly.

Executable File IMAGE_OPTIONAL_HEADER ImageBase is 0

I've encountered a problem I am trying to figure out for a while now but I am unable to find anything about it, I am trying to get a mapped file image base from its optional header found in the PE header but the value in the ImageBase is 0?
The file I am trying to get this value from is a 64 bit executable (PE64), so what I am doing is I open the file with (CreateFileW function), then I map it using (CreateFileMappingW and MapViewOfFile functions), then I get the PE Header file with these functions:
IMAGE_DOS_HEADER* FileUtils_GetFileDOSHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
return (IMAGE_DOS_HEADER*) Arg_FileViewMap;
}
return NULL;
}
IMAGE_NT_HEADERS* FileUtils_GetFilePEHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
IMAGE_DOS_HEADER* Func_FileDOSHeader = FileUtils_GetFileDOSHeader(Arg_FileViewMap);
if (Func_FileDOSHeader != NULL) {
return (IMAGE_NT_HEADERS*) ((INT64) Func_FileDOSHeader + Func_FileDOSHeader->e_lfanew);
}
}
return NULL;
}
Then I use this function to get the optional header or do it directly, same result:
IMAGE_OPTIONAL_HEADER* FileUtils_GetFileOptionalHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
IMAGE_NT_HEADERS* Arg_FilePEHeader = FileUtils_GetFilePEHeader(Arg_FileViewMap);
if (Arg_FilePEHeader != NULL) {
return (IMAGE_OPTIONAL_HEADER*) &Arg_FilePEHeader->OptionalHeader;
}
}
return NULL;
}
Then I try to get value and print it out so I would know that its not 0 like so:
wprintf(L"File image base: 0x%015X\n", FileUtils_GetFileOptionalHeader(Func_TargetFileViewMap)->ImageBase);
That is all! Once I compile this code for 64bit and run it, it prints out 0 but it should give me 0x00000010000000, so what is wrong here? The value does print out correctly, I made sure that the value is indeed 0 a lot of times.
Now things to note:
Some executables do give me the ImageBase value, but most of them give me 0 even though that is wrong, for example I open notepad and that gives me 0 but the value should be 0x00000010000000, and to show you that here is a screenshot of what CFF Explorer sees: (http://prntscr.com/) <- Click
It appears that all other values are correct except the ImageBase that is 0 for some reason, if I print out the EntryPoint then the value does match with what the CFF Explorer tells me.
I am using GCC (From MinGW-w64) compiler (C Programming Language) for this
I am not aware of any other invalid values in other headers, its just the ImageBase getting me frustrated.
A quick thing, if you also need to know what the function parameters for opening and mapping the file are then here they are:
HANDLE Func_TargetFile = CreateFileW((wchar_t*) & Func_ConsoleCommand, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE Func_TargetFileMapping = CreateFileMappingW(Func_TargetFile, NULL, PAGE_READWRITE, 0, 0, NULL);
void* Func_TargetFileViewMap = MapViewOfFile(Func_TargetFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
That is all, once again if you are confused of what my question is: Why does the IMAGE_OPTIONAL_HEADER ImageBase gives me a value of 0 even though all other values in the header seem to match what CFF Explorer shows me? - Thank you
PS: I will check consistently, if you need more information then comment below.
I have solved the mistery, it was in the GetFilePEHeader function! The printed out value is now: 0x000000005F5E100
The issue was with the casting, this line of code:
return (IMAGE_NT_HEADERS*) ((char*) (Func_FileDOSHeader) + Func_FileDOSHeader->e_lfanew);
Here is the fixed function:
IMAGE_NT_HEADERS* FileUtils_GetFilePEHeader (void* Arg_FileViewMap) {
if (Arg_FileViewMap != NULL) {
IMAGE_DOS_HEADER* Func_FileDOSHeader = FileUtils_GetFileDOSHeader(Arg_FileViewMap);
if (Func_FileDOSHeader != NULL) {
return (IMAGE_NT_HEADERS*) ((INT64) Func_FileDOSHeader + Func_FileDOSHeader->e_lfanew);
}
}
return NULL;
}
Thank you all for all of your help, this was quite a dumb issue. It took me 3 days to figure this out.

git diff of just one file

The only way I found to get a diff from a single file using libgit2 is through git_diff_foreach and checking the filename at the diff_file_cb callback.
It's not the way I wanted to do this, I was looking for something easier.
Is there another way to do this?
Just to clarify, git_diff_index_to_workdir (or git_diff_tree_to_tree or another such function) finds the list of changed files and then git_diff_foreach walks through the found files and the text of the diffs. You can pass a "pathspec" in the options structure for git_diff_index_to_workdir that will limit the files being checked. You would do that as mentioned in the prior answer.
As a slightly broader example, if you wanted to diff a more complex set of files, you could write something like:
git_diff *diff;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
char *files[3];
files[0] = "myfile.txt";
files[1] = "yourfile.txt";
files[2] = "some/directory/*.h"
opts.pathspec.count = 3;
opts.pathspec.strings = files;
if (git_diff_index_to_workdir(&diff, repo, NULL, &opts) < 0) {
printf("Failed to diff\n");
exit(1);
}
git_diff_foreach(diff, file_cb, NULL, NULL, NULL);
git_diff_free(diff);
You can pass as many file names or file patterns as you like. If you want to disable the pattern matching behavior (i.e. expanding * and such), you can write opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH and only exact file name matches will be used.
Much easier using the pathspec option and git_diff_index_to_workdit instead of git_diff_foreach
char *pathspec = "foo.bar";
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
opts.pathspec.strings = &pathspec;
opts.pathspec.count = 1;
git_diff_index_to_workdir(&diff, repo, NULL, &opts);

How to get mounted drive's volume name in linux using C?

I'm currently working on program, which must display information about mounted flash drive. I want to display full space, free space, file system type and volume name. But problem is that, i can't find any API through which i can get volume name(volume label). Is there any api to do this?
p.s. full space, free space and file system type i'm getting via statfs function
Assuming that you work on a recent desktop-like distribution (Fedora, Ubuntu, etc.), you have HAL daemon running and a D-Bus session.
Within org.freedesktop.UDisks namespace you can find the object that represents this drive (say org/freedekstop/UDisks/devices/sdb/. It implements org.freedesktop.UDisks.interface. This interface has all the properties that you can dream of, including UUID (IdUuid), FAT label (IdLabel), all the details about filesystem, SMART status (if the drive supports that) etc. etc.
How to use D-Bus API in C is a topic for another question. I assume that's been already discussed in detail -- just search [dbus] and [c] tags.
Flash drives are generally FAT32, which means the "name" that you're looking for is probably the FAT drive label. The most common linux command to retrieve that information is mlabel from the mtools package.
The command looks like this:
[root#localhost]$ mlabel -i /dev/sde1 -s ::
Volume label is USB-DISK
This program works by reading the raw FAT header of the filesystem and retrieving the label from that data. You can look at the source code for the applciation to see how you can replicate the parsing of FAT data in your own application... or you can simply execute run the mlabel binary and read the result into your program. The latter sounds simpler to me.
To call the methods:
kernResult = self->FindEjectableCDMedia(&mediaIterator);
if (KERN_SUCCESS != kernResult) {
printf("FindEjectableCDMedia returned 0x%08x\n", kernResult);
}
kernResult = self->GetPath(mediaIterator, bsdPath, sizeof(bsdPath));
if (KERN_SUCCESS != kernResult) {
printf("GetPath returned 0x%08x\n", kernResult);
}
and the methods:
// Returns an iterator across all DVD media (class IODVDMedia). Caller is responsible for releasing
// the iterator when iteration is complete.
kern_return_t ScanPstEs::FindEjectableCDMedia(io_iterator_t *mediaIterator)
{
kern_return_t kernResult;
CFMutableDictionaryRef classesToMatch;
// CD media are instances of class kIODVDMediaTypeROM
classesToMatch = IOServiceMatching(kIODVDMediaClass);
if (classesToMatch == NULL) {
printf("IOServiceMatching returned a NULL dictionary.\n");
} else {
CFDictionarySetValue(classesToMatch, CFSTR(kIODVDMediaClass), kCFBooleanTrue);
}
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, mediaIterator);
return kernResult;
}
// Given an iterator across a set of CD media, return the BSD path to the
// next one. If no CD media was found the path name is set to an empty string.
kern_return_t GetPath(io_iterator_t mediaIterator, char *Path, CFIndex maxPathSize)
{
io_object_t nextMedia;
kern_return_t kernResult = KERN_FAILURE;
DADiskRef disk = NULL;
DASessionRef session = NULL;
CFDictionaryRef props = NULL;
char * bsdPath = '\0';
*Path = '\0';
nextMedia = IOIteratorNext(mediaIterator);
if (nextMedia) {
CFTypeRef bsdPathAsCFString;
bsdPathAsCFString = IORegistryEntryCreateCFProperty(nextMedia,CFSTR(kIOBSDNameKey),kCFAllocatorDefault,0);
if (bsdPathAsCFString) {
//strlcpy(bsdPath, _PATH_DEV, maxPathSize);
// Add "r" before the BSD node name from the I/O Registry to specify the raw disk
// node. The raw disk nodes receive I/O requests directly and do not go through
// the buffer cache.
//strlcat(bsdPath, "r", maxPathSize);
size_t devPathLength = strlen(bsdPath);
if (CFStringGetCString( (CFStringRef)bsdPathAsCFString , bsdPath + devPathLength,maxPathSize - devPathLength, kCFStringEncodingUTF8)) {
qDebug("BSD path: %s\n", bsdPath);
kernResult = KERN_SUCCESS;
}
session = DASessionCreate(kCFAllocatorDefault);
if(session == NULL) {
qDebug("Can't connect to DiskArb\n");
return -1;
}
disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, bsdPath);
if(disk == NULL) {
CFRelease(session);
qDebug( "Can't create DADisk for %s\n", bsdPath);
return -1;
}
props = DADiskCopyDescription(disk);
if(props == NULL) {
CFRelease(session);
CFRelease(disk);
qDebug("Can't get properties for %s\n",bsdPath);
return -1;
}
CFStringRef daName = (CFStringRef )CFDictionaryGetValue(props, kDADiskDescriptionVolumeNameKey);
CFStringGetCString(daName,Path,sizeof(Path),kCFStringEncodingUTF8);
if(daName) {
qDebug("%s",Path);
CFRetain(daName);
}
CFRelease(daName);
CFRelease(props);
CFRelease(disk);
CFRelease(session);
CFRelease(bsdPathAsCFString);
}
IOObjectRelease(nextMedia);
}
return kernResult;
}

Safely remove a USB drive using the Win32 API?

How do I remove a USB drive using the Win32 API? I do a lot of work on embedded systems and on one of these I have to copy my programs on a USB stick and insert it into the target hardware.
Since I mostly work on the console I don't like to use the mouse and click on the small task-bar icon hundred times a day.
I'd love to write a little program to do exactly that so I can put it into my makefiles, but I haven't found any API call that does the same thing.
Any ideas?
You can use the CM_Request_Device_Eject() function as well as some other possibilities.
Consult the following projects and articles:
DevEject: Straightforward.
http://www.withopf.com/tools/deveject/
A useful CodeProject article:
http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx
It looks like Sync lets you specify -e to eject removable drives. While not a win32 API, you could probably just call sync -e [drive_letter] from your makefile.
Here is a technet article about removable storage media. Look for DismountNtmsMedia.
Here's a solution in Delphi, that I've modified and put into a service for use in a very large enterprise. Go to: link text
Look for "scapi (Setup & Config Manager API)", and download it. There will be a demo program called USBView that will get you on your way. If you have Delphi, this also includes a TUSBDeviceTree component that you can use to gather information about a USB device when.
Regards
#include<SetupAPI.h>
#include <windows.h>
#include<initguid.h>
#include <newdev.h>
#include <Cfgmgr32.h>
#pragma comment(lib, "Cfgmgr32.lib")
#pragma comment(lib, "Setupapi.lib")
#pragma comment(lib, "Newdev.lib")
int RemoveDevice(const GUID *guid, const wchar_t *hwID) {
HDEVINFO m_hDevInfo;
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD dwSize;
BYTE Buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
printf("try to remove device::%ws\n", hwID);
m_hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT| DIGCF_DEVICEINTERFACE);
if (m_hDevInfo == INVALID_HANDLE_VALUE)
{
printf("GetClassDevs Failed!\n");
return 0;
}
spdid.cbSize = sizeof(spdid);
for (int i = 0; SetupDiEnumDeviceInterfaces(m_hDevInfo, NULL, guid, i, &spdid); i++) {
dwSize = 0;
SetupDiGetDeviceInterfaceDetail(m_hDevInfo,
&spdid, NULL, 0, &dwSize, NULL);
if (dwSize != 0 && dwSize <= sizeof(Buf)) {
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
ZeroMemory((PVOID)&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
long res =
SetupDiGetDeviceInterfaceDetail(m_hDevInfo, &
spdid, pspdidd,
dwSize, &dwSize,
&spdd);
if (res) {
OLECHAR* guidString;
OLECHAR* guidString2;
StringFromCLSID(&spdd.ClassGuid, &guidString);
StringFromCLSID(&spdid.InterfaceClassGuid, &guidString2);
printf("%d, %ws, %ws, %ws\n", spdd.DevInst, pspdidd->DevicePath, guidString, guidString2);
CoTaskMemFree(guidString);
CoTaskMemFree(guidString2);
if (!memcmp(pspdidd->DevicePath, hwID, 2 * lstrlenW(hwID))) {
DEVINST DevInstParent = 0;
res = CM_Get_Parent(&DevInstParent, spdd.DevInst, 0);
for (long tries = 0; tries < 10; tries++) {
// sometimes we need some tries...
WCHAR VetoNameW[MAX_PATH];
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
VetoNameW[0] = 0;
res = CM_Request_Device_EjectW(DevInstParent,
&VetoType, VetoNameW, MAX_PATH, 0);
if ((res == CR_SUCCESS &&
VetoType == PNP_VetoTypeUnknown)) {
printf("remove %ws success!\n", pspdidd->DevicePath);
SetupDiDestroyDeviceInfoList(m_hDevInfo);
return 1;
}
Sleep(500); // required to give the next tries a chance!
}
break;
}
}
}
}
printf("Remove Device Failed!\n");
SetupDiDestroyDeviceInfoList(m_hDevInfo);
return 0;
}
int main(){
GUID GUID_DEVINTERFACE_USB_HUB;
CLSIDFromString(L"F18A0E88-C30C-11D0-8815-00A0C906BED8", &GUID_DEVINTERFACE_USB_HUB);
RemoveDevice(&GUID_DEVINTERFACE_USB_HUB, L"\\\\?\\usb#root_hub30");
return 0;
}
refrences:
How to Prepare a USB Drive for Safe Removal
GUID_DEVINTERFACE

Resources