// If there is Reprase data already, it still writes new Reparse data bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) { NFile::NFind::CFileInfo fi; if (fi.Find(path)) { if (fi.IsDir() != isDir) { ::SetLastError(ERROR_DIRECTORY); return false; } } else { if (isDir) { if (!NDir::CreateComplexDir(path)) return false; } else { CreatePrefixDirOfFile(path); COutFile file; if (!file.Create(path, CREATE_NEW)) return false; } } COutFile file; if (!file.Open(path, FILE_SHARE_WRITE, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) return false; DWORD returnedSize; if (!file.DeviceIoControl(my_FSCTL_SET_REPARSE_POINT, (void *)data, size, NULL, 0, &returnedSize)) return false; return true; }
//TODO: clean and optimize! STDMETHODIMP ExtractCallback::GetStream( UInt32 index, ISequentialOutStream** outStream, Int32 askExtractMode ) { *outStream = 0; mOutFileStream.Release(); // Get Name NCOM::CPropVariant prop; RINOK( mArchiveHandler->GetProperty( index, kpidPath, &prop ) ); wstring fullPath; if ( prop.vt == VT_EMPTY ) { fullPath = kEmptyFileAlias; } else { if ( prop.vt != VT_BSTR ) { return E_FAIL; } fullPath = prop.bstrVal; } mFilePath = fullPath; if ( askExtractMode != NArchive::NExtract::NAskMode::kExtract ) { return S_OK; } // Get Attrib NCOM::CPropVariant prop2; RINOK( mArchiveHandler->GetProperty( index, kpidAttrib, &prop2 ) ); if ( prop2.vt == VT_EMPTY ) { mProcessedFileInfo.Attrib = 0; mProcessedFileInfo.AttribDefined = false; } else { if ( prop2.vt != VT_UI4 ) { return E_FAIL; } mProcessedFileInfo.Attrib = prop2.ulVal; mProcessedFileInfo.AttribDefined = true; } RINOK( IsArchiveItemFolder( mArchiveHandler, index, mProcessedFileInfo.isDir ) ); // Get Modified Time NCOM::CPropVariant prop3; RINOK( mArchiveHandler->GetProperty( index, kpidMTime, &prop3 ) ); mProcessedFileInfo.MTimeDefined = false; switch ( prop3.vt ) { case VT_EMPTY: // mProcessedFileInfo.MTime = _utcMTimeDefault; break; case VT_FILETIME: mProcessedFileInfo.MTime = prop3.filetime; mProcessedFileInfo.MTimeDefined = true; break; default: return E_FAIL; } // Get Size NCOM::CPropVariant prop4; RINOK( mArchiveHandler->GetProperty( index, kpidSize, &prop4 ) ); bool newFileSizeDefined = ( prop4.vt != VT_EMPTY ); UInt64 newFileSize; if ( newFileSizeDefined ) { //taken from ConvertPropVariantToUInt64 switch ( prop4.vt ) { case VT_UI1: newFileSize = prop4.bVal; break; case VT_UI2: newFileSize = prop4.uiVal; break; case VT_UI4: newFileSize = prop4.ulVal; break; case VT_UI8: newFileSize = ( UInt64 )prop4.uhVal.QuadPart; break; default: mErrorMessage = L"151199"; return E_FAIL; } //newFileSize = ConvertPropVariantToUInt64( prop4 ); } // Create folders for file size_t slashPos = mFilePath.rfind( WSTRING_PATH_SEPARATOR ); if ( slashPos != wstring::npos ) { NFile::NDir::CreateComplexDir( ( mDirectoryPath + mFilePath.substr( 0, slashPos ) ).c_str() ); } wstring fullProcessedPath = mDirectoryPath + mFilePath; mDiskFilePath = fullProcessedPath; if ( mProcessedFileInfo.isDir ) { NFile::NDir::CreateComplexDir( fullProcessedPath.c_str() ); } else { NFile::NFind::CFileInfo fi; if ( mOpener.fileCallback() ) { wstring filename; filesystem::fsutil::filename( fullProcessedPath, filename, true ); mOpener.fileCallback()( filename ); } if ( fi.Find( fullProcessedPath.c_str() ) ) { if ( !NFile::NDir::DeleteFileAlways( fullProcessedPath.c_str() ) ) { //cerr << UString( kCantDeleteOutputFile ) << fullProcessedPath << endl; //throw BitException( kCantDeleteOutputFile + fullProcessedPath ); mErrorMessage = kCantDeleteOutputFile + fullProcessedPath; return E_ABORT; } } mOutFileStreamSpec = new COutFileStream; CMyComPtr< ISequentialOutStream > outStreamLoc( mOutFileStreamSpec ); if ( !mOutFileStreamSpec->Open( fullProcessedPath.c_str(), CREATE_ALWAYS ) ) { //cerr << ( UString )L"cannot open output file " + fullProcessedPath << endl; //throw BitException( L"cannot open output file " + fullProcessedPath ); mErrorMessage = L"Cannot open output file " + fullProcessedPath; return E_ABORT; } mOutFileStream = outStreamLoc; *outStream = outStreamLoc.Detach(); } return S_OK; }