From 0f761d0edd9cdfd7fe5dcfe1350e5b0bae26f5ae Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Tue, 25 Aug 2020 14:17:55 +0900 Subject: [PATCH 01/16] Fix static analysis(TOCTOU) issue Change-Id: I18dfdee7f6ca2dc0e7676b95b84aece3b3208fb9 Signed-off-by: Junghyun Yeon --- src/wgt/step/encryption/step_encrypt_resources.cc | 28 +++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/wgt/step/encryption/step_encrypt_resources.cc b/src/wgt/step/encryption/step_encrypt_resources.cc index c5bbb9b..40b6781 100644 --- a/src/wgt/step/encryption/step_encrypt_resources.cc +++ b/src/wgt/step/encryption/step_encrypt_resources.cc @@ -13,7 +13,9 @@ #include #include + #include +#include #include #include @@ -160,22 +162,28 @@ bool StepEncryptResources::Encrypt(const bf::path &src) { bool StepEncryptResources::EncryptFile(const bf::path &src) { struct stat info; memset(&info, 0, sizeof(info)); - if (stat(src.c_str(), &info) != 0) { + int fd; + + FILE *input = OpenFile(src, "rb"); + if (!input) { + LOG(ERROR) << "Cannot open file for encryption: " << src; + return false; + } + + fd = fileno(input); + if (fstat(fd, &info) != 0) { LOG(ERROR) << "Could not access file " << src; + fclose(input); return false; } + const std::size_t fileSize = info.st_size; if (0 == fileSize) { LOG(ERROR) << src << " size is 0, so encryption will be skipped"; + fclose(input); return true; } - FILE *input = OpenFile(src, "rb"); - if (!input) { - LOG(ERROR) << "Cannot open file for encryption: " << src; - return false; - } - bf::path encFile(src.string() + ".enc"); FILE *output = OpenFile(encFile, "wb"); if (!output) { @@ -263,11 +271,13 @@ bool StepEncryptResources::EncryptFile(const bf::path &src) { } while (!std::feof(input)); fclose(output); - fclose(input); LOG(DEBUG) << "File encrypted successfully"; - if (0 != unlink(src.c_str())) + if (0 != unlink(src.c_str())) { + fclose(input); return false; + } + fclose(input); LOG(DEBUG) << "Rename encrypted file"; if (0 != std::rename(encFile.c_str(), src.c_str())) -- 2.7.4 From 2e93f935ed90190f1bd93d9b32e2b5035c62a793 Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Wed, 2 Sep 2020 15:43:42 +0900 Subject: [PATCH 02/16] Fix StepWgtPreparePackageDirectory The unpacked dir path should not be changed. The extracted files will be recovered without changing unpacked dir path Change-Id: I696fd99acff2ec8d825188166aa4a9c94b7b6fd6 Signed-off-by: Ilho Kim --- src/wgt/step/filesystem/step_wgt_prepare_package_directory.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/wgt/step/filesystem/step_wgt_prepare_package_directory.cc b/src/wgt/step/filesystem/step_wgt_prepare_package_directory.cc index 5b2bb0f..4e90b29 100644 --- a/src/wgt/step/filesystem/step_wgt_prepare_package_directory.cc +++ b/src/wgt/step/filesystem/step_wgt_prepare_package_directory.cc @@ -78,11 +78,6 @@ ci::Step::Status StepWgtPreparePackageDirectory::ExtractEntries() { bf::path backup_path = ci::GetBackupPathForPackagePath(context_->GetPkgPath()); backupPath_ = backup_path; - if (context_->request_type.get() == ci::RequestType::MountUpdate && - context_->recovery_info.get().recovery_file) { - context_->recovery_info.get().recovery_file->set_unpacked_dir(backup_path); - context_->recovery_info.get().recovery_file->WriteAndCommitFileContent(); - } bf::path resource_path = context_->GetPkgPath() / kResWgtDirectory; bs::error_code error; -- 2.7.4 From c5ffe2c7688881058aa6b90d64b70440fc020674 Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Tue, 25 Aug 2020 18:03:17 +0900 Subject: [PATCH 03/16] Fix extensive smoke test - Handle the cleanup recovery type - Fix RecoveryMode_ForMountInstall.wgt package's appid correctly Change-Id: I46d9d7dcdbddd9191ec1049b067a47141e786cdf Signed-off-by: Ilho Kim --- test/smoke_tests/extensive_smoke_test.cc | 60 +++++++++++++++++++-- test/smoke_tests/smoke_test_helper.cc | 14 ++--- .../smoke/RecoveryMode_ForMountInstall.wgt | Bin 38021 -> 38508 bytes 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/test/smoke_tests/extensive_smoke_test.cc b/test/smoke_tests/extensive_smoke_test.cc index 4fc3275..444fbd9 100644 --- a/test/smoke_tests/extensive_smoke_test.cc +++ b/test/smoke_tests/extensive_smoke_test.cc @@ -97,9 +97,17 @@ TEST_F(SmokeTest, RecoveryMode_ForInstallation) { bf::path recovery_file = FindRecoveryFile("/wgt-recovery", params.test_user.uid); EXTENDED_ASSERT_FALSE(recovery_file.empty()); + std::unique_ptr recovery_info = + GetRecoverFileInfo(recovery_file); EXTENDED_ASSERT_EQ(backend.Recover(recovery_file), ci::AppInstaller::Result::OK); - EXTENDED_ASSERT_TRUE(CheckPackageNonExistance(pkgid, params)); + if (recovery_info->cleanup()) { + EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, {appid}, params)); + EXTENDED_ASSERT_EQ(backend.Uninstall(pkgid), + ci::AppInstaller::Result::OK); + } else { + EXTENDED_ASSERT_TRUE(CheckPackageNonExistance(pkgid, params)); + } } return true; }, params.pkg_type); @@ -122,13 +130,24 @@ TEST_F(SmokeTest, RecoveryMode_ForUpdate) { bf::path recovery_file = FindRecoveryFile("/wgt-recovery", params.test_user.uid); EXTENDED_ASSERT_FALSE(recovery_file.empty()); + std::unique_ptr recovery_info = + GetRecoverFileInfo(recovery_file); EXTENDED_ASSERT_EQ(backend.Recover(recovery_file), ci::AppInstaller::Result::OK); EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, {appid}, params)); + std::string version = recovery_info->cleanup() ? "2\n" :"1\n"; EXTENDED_ASSERT_TRUE(ValidateFileContentInPackage(pkgid, - "res/wgt/VERSION", "1\n", params)); + "res/wgt/VERSION", version, params)); EXTENDED_ASSERT_TRUE(ValidateDataFiles(pkgid, params.test_user.uid)); + + if (recovery_info->cleanup()) { + EXTENDED_ASSERT_EQ(backend.Uninstall(pkgid), + ci::AppInstaller::Result::OK); + EXTENDED_ASSERT_EQ(backend.Install(path_old), + ci::AppInstaller::Result::OK); + AddDataFiles(pkgid, params.test_user.uid); + } } return true; }, params.pkg_type); @@ -150,13 +169,24 @@ TEST_F(SmokeTest, RecoveryMode_ForDelta) { bf::path recovery_file = FindRecoveryFile("/wgt-recovery", params.test_user.uid); EXTENDED_ASSERT_FALSE(recovery_file.empty()); + std::unique_ptr recovery_info = + GetRecoverFileInfo(recovery_file); EXTENDED_ASSERT_EQ(backend.Recover(recovery_file), ci::AppInstaller::Result::OK); EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, {appid}, params)); + std::string contents = recovery_info->cleanup() ? "2\n" : "1\n"; EXTENDED_ASSERT_TRUE(ValidateFileContentInPackage(pkgid, - "res/wgt/VERSION", "1\n", params)); + "res/wgt/VERSION", contents, params)); EXTENDED_ASSERT_TRUE(ValidateDataFiles(pkgid, params.test_user.uid)); + + if (recovery_info->cleanup()) { + EXTENDED_ASSERT_EQ(backend.Uninstall(pkgid), + ci::AppInstaller::Result::OK); + EXTENDED_ASSERT_EQ(backend.Install(path_old), + ci::AppInstaller::Result::OK); + AddDataFiles(pkgid, params.test_user.uid); + } } return true; }, params.pkg_type); @@ -175,9 +205,18 @@ TEST_F(SmokeTest, RecoveryMode_ForMountInstall) { bf::path recovery_file = FindRecoveryFile("/wgt-recovery", params.test_user.uid); EXTENDED_ASSERT_FALSE(recovery_file.empty()); + std::unique_ptr recovery_info = + GetRecoverFileInfo(recovery_file); EXTENDED_ASSERT_EQ(backend.Recover(recovery_file), ci::AppInstaller::Result::OK); - EXTENDED_ASSERT_TRUE(CheckPackageNonExistance(pkgid, params)); + ScopedTzipInterface interface(pkgid, params.test_user.uid); + if (recovery_info->cleanup()) { + EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, {appid}, params)); + EXTENDED_ASSERT_EQ(backend.Uninstall(pkgid), + ci::AppInstaller::Result::OK); + } else { + EXTENDED_ASSERT_TRUE(CheckPackageNonExistance(pkgid, params)); + } } return true; }, params.pkg_type); @@ -206,14 +245,25 @@ TEST_F(SmokeTest, RecoveryMode_ForMountUpdate) { bf::path recovery_file = FindRecoveryFile("/wgt-recovery", params.test_user.uid); EXTENDED_ASSERT_FALSE(recovery_file.empty()); + std::unique_ptr recovery_info = + GetRecoverFileInfo(recovery_file); EXTENDED_ASSERT_EQ(backend.Recover(recovery_file), ci::AppInstaller::Result::OK); ScopedTzipInterface interface(pkgid, params.test_user.uid); EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, {appid}, params)); + std::string version = recovery_info->cleanup() ? "2\n" : "1\n"; EXTENDED_ASSERT_TRUE(ValidateFileContentInPackage( - pkgid, "res/wgt/VERSION", "1\n", params)); + pkgid, "res/wgt/VERSION", version, params)); EXTENDED_ASSERT_TRUE(ValidateDataFiles(pkgid, params.test_user.uid)); + if (recovery_info->cleanup()) { + interface.Release(); + EXTENDED_ASSERT_EQ(backend.Uninstall(pkgid), + ci::AppInstaller::Result::OK); + EXTENDED_ASSERT_EQ(backend.MountInstall(path_old), + ci::AppInstaller::Result::OK); + AddDataFiles(pkgid, params.test_user.uid); + } } return true; }, params.pkg_type); diff --git a/test/smoke_tests/smoke_test_helper.cc b/test/smoke_tests/smoke_test_helper.cc index 1bd7d80..a52afa2 100644 --- a/test/smoke_tests/smoke_test_helper.cc +++ b/test/smoke_tests/smoke_test_helper.cc @@ -19,8 +19,14 @@ int main(int argc, char** argv) { std::string step_name; smoke_test::CrashStepType type = smoke_test::CrashStepType::PROCESS; + if (!strcmp(argv[backend_argc - 1], "-type_clean")) { + backend_argc--; + type = smoke_test::CrashStepType::CLEAN; + LOG(DEBUG) << "step will be crashed in clean operation"; + } + if (!strcmp(argv[backend_argc - 2], "-idx")) { - index = atoi(argv[argc - 1]); + index = atoi(argv[backend_argc - 1]); backend_argc -= 2; LOG(DEBUG) << "Step crash after " << index << " step."; } @@ -31,12 +37,6 @@ int main(int argc, char** argv) { LOG(DEBUG) << "Step crash after " << step_name << " step."; } - if (!strcmp(argv[backend_argc - 1], "-type_clean")) { - backend_argc--; - type = smoke_test::CrashStepType::CLEAN; - LOG(DEBUG) << "step will be crashed in clean operation"; - } - ci::PkgmgrInstaller pkgmgr_installer; wgt::WgtAppQueryInterface query_interface; auto pkgmgr = ci::PkgMgrInterface::Create(backend_argc, argv, diff --git a/test/smoke_tests/test_samples/smoke/RecoveryMode_ForMountInstall.wgt b/test/smoke_tests/test_samples/smoke/RecoveryMode_ForMountInstall.wgt index 14c8562f7946c138a2a8c7bdc91b14c978f750a2..7da0b98aa3441ddf5a9ddc3ff43140cb64f07d7a 100644 GIT binary patch delta 6852 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 delta 6512 zcmZvgby!qe_s54Ax+DZ?WI&`Fq=lhDx|D7NhAxRCAkxy^Al)!ZNl14~4c#C}NvSwL zyuW+z>%H&0o@bxE=REUW>+H4GAM5!XRG@~Gq7tYpqoI?6u&}T|N};Ms34|~C(0?83 zT?O{!|2QR>_)`KNnvY=!ZXz+|YW-t#N_@*=DK1aa+)6Zv)Fkyf;rRN3IeQ$6qJa)B zvQ=3rH%o>Py+3V!%k}jGvyVPzH@fc{N7dXbo>#ot;4xv(hMy|&?-O>mO(p5c$tT^X z9(;w8)3qY@jNSBmvyV}wsf8)`Qc2|b{lVoC&N0@4EV~-Ob~vz}K6hP-A74qZSXqXg zfoT={9iTf}AcyN~@o|cx`AdxOW*WcFYLUe~+$G0wVq)$~}4Ol~dTH(-r+Xry{_ zhiAS>UEI(InqJkrzNG6L1sXckt-`s;c>`r3|MpxzaSucuq z%6U+*2$%;dZ zau}HN|7l>-tI)qqYBUH8bHDu@O^T){a8YxIcH=v$1_{N0X&)o_z&ncF`B308-+gDI zP})nijlt)>Jg;^kS04h@q!x>-u9Q(mM~R1^>q^)J_)4F&jQSQh*_=t+4I*8>pBmN; zn1AEtcr!BtpJP2(fV)k(ud#_nF~^38J#s}eY3B$&(epH7)|%jYhgr2s085#|WSi&x zsym(GTE8n=-nEyBL{nGB#B$x3yf=vg0>RKgpntXk=r>DH7GMN^wZ(7mKsdKQESzB0 zb~c>ejt-8okJY;Ai9(KU$X>OW9`^7reHrNv780jouU{ItTOyURU+p#MnISNUz3qRt z%`*}ph$b3LxO?y>Wj&j(CTq&}I}PCL-|V~j{k<*mKJ9(Rxz{4=LPUO1E)|8tTx)(@ zfMYB<=P_;*&qJoTGD)KS=quNR*-;iaFNIgobYDCY=RH)E5wgJ_Td%=KNm=Rhj9Wx? zRHNL5x<)Imx$fpu1#3?|z6QR`jB)>~dJT^UpSn1D(n80u#dj|quYyY&4U64J|T zZR_H!zzdVQsw?_?Zr|ie1)EbO-LLH4uObg3yv^?M?fPeSYYAL=_5W8!?O>Kx-ki4X zjt=!2?k8RZ;dstE{VW3`wHtMT8l~Y6rIhG8!MDyZu@)_-q^WOfzJCl?OpTz>J^-EHb> zi9#8q+NhI3m-##O4hwCAh^!&tVC)Rqzj88uMW&BF6xBuN~ zG6)HRnses!xizYr{Hd^ekov`e+<}>VV0z8Xvc=pk$~;!#xHgGvh@(trpBB;3EWN^0 z@5hlkhp&|wHtnr^Y_$2C2kH)9@!dCSrmm7(e+qaVQ^%J(Uzx^m3;)oSlkpyZ!Z)=nf^)i5cG2{|>N){zm+tH@+5Yl;kB z^fas%nQFRKe%Nkp|E$$hM_r_>FX{ev?e5RC0!t4OVum$uysy*)Kf;8BN=*P*pCcJ) z+1}uifaP>UJIyarDK2~MDMyRL&ogQpKDQBD+tkt^qoqq_>zzlvo^(ihd`+sAZ(07Q zJHc4j!mxntL)>50ee5LxO}T9wboBqKuG~v{VBR%jf!KeCP4mgpgQStSA4QVhKIg*{ z#DWk>2c=w7h|no&e>OlW-MkU?%NVeSUBS#;L1O1D(it%End;GXWCt~YUuTW#Pv z0)+;YBD&NBx@6X+n>vrT13jPxN zTJ2u+h<`lUa$i3D%TULC>$AuLx??%QGOtq{E{_j{zGMMy_4^veizz~_p?3~Cv#|ZE zE0*u|V0}NyIGQEm3Tq~tT_#V&W#*Vr2U2fRO+#r+XK^|nW=cfP^Gx!-PmE&EK|~+G zbDX5~ls8Gfb*|b7K1t4&Mvghx*eHh$91oXM?FqZ!J1+ycUM49;sWxh0U_p~S6p{Q4YaQQ_I>MdWm$Nq!4n@3JQ&-#Q%k^x{l}0}jo{ zM$k?kDng%qa_kkx3UGgYYXm||E zkr5bwGl{?Aa~CVpPeHTxSFns^ZAlQi-yjLlDxD555sOz4b}aBo{jjR@tj!{TLDDod$3tzB40 z#zKquZZ_aq=n}NzN>r_e-F0bTqc9>B5i5$XjlyUvNo0mBPed)bh$B2 zSfy`QXz8s|i>5=?8H=}o!-}ZRnb$#9bQ}_Qhna|#&cF?B1WntxXi+iG9KYT3dFSI~ zDO-&kJQVIqj?ytOp|h(l>74SWERhqymKM2ZOL>K($~Jt5lfYh22%(O~yOom@t_&t_?K10wO6B_*$g`{}Cvt9Z)>be9RtvlxrtY$9_j2vO zOgJ8di7O~XLLuT3xSg&F;mE089(u4ysE|@ zCC1OemqIKE-H2C*3X;pm>bQk!`*w?9H4bt3_75gPRb!%hFXA!2MfVaAGrl`zrLsCU zU?$|Mo1x=-Oeoa|j2FDj3v_!YW2_NeUE&BCH*Qx(R9(D%vd|5GCTj`^j6&q}+_)y} z8#OILwf(>rqUdrR?W~E!URqa_7s}Jscu)+8p1W+bV5iawM zpTzumY6@>-P6i&?Fubt2hxgquTV9%MTt!m0IUB=!KA|t$wqqf(C5=3?daRF_K2g_o zF~&f^pSa?)Y88G6BGl#`v(@Yz8!n|dL=?69Gp1)x@2#*~B46D}?{%8Fe=qfOX8nsu zyG~=l()k&GK+_NhyRM!B-?TB23Um+y*VTK2qkm#gZ3i6+6VsnLaH-ncZ@ajbIfP*Xp_ODFm6^0M2r=k|!u9qAw6VKH(hw{-AXe-RC{}Ym zv{GgplO3w9tXYl$M=r7^W2~@V%#4saw+YlghnL&;#GHp7Ra(#@7~To>J@ti^W=-Ee zj%Wj{OZ<>j(HY8cH+w^5U$1Nc3?;9&nq&MlkWrcP0D>_JQGH%$yF$xZw`(BR)}R0R zgLHsE&Ch|~x3&zuSkar*PcGDG+*_MN3It?vr)0e{f(rypQxw|1Bya1<{xT$B?&N$x6yY5eKvEu;&(A)83iN1oSzFyvFQjl z(30bQFD2(usS_rIJaA2w>NEPp_piDcxdl z$zrMSVZHXwc~BVJNz_qM*98Pyn$I6%n^dso&NRBj5~eJSU+WQaCw^4VJAD};uG_A757h?5)CwWQgM*X@hE z$R3ydt+F))kXoSi5?ai6O6*{1O&&~{4Q=BB{+RD;Rko(@Vu3(!i2rMh=m}>A3}Q0+DgAf!pfpPl z%DdL_W8xKh-td@mTb~S(Wf%;%byd?XDqgztW{FNsX8F`uMpTbBXlH5BonMoJ)0W^# zNHc|mil3)Mf~qG}c$fajQj>tea!@Z3dSD!l7?rmNsh{6fhp!2(6ylZ7Iq%IH+t=%# ztG<4oBRiOrqo?eE>mellfO(K_BImG`kRJP#^?B!4@@#bq*)Q3&Hy{1oCv+}O);`-@ zIo2F;=KMf9dRv}n_FJUu{p>4yPxpDecP68yAm`Ycunah7lXSZwv`Ipqu5Ql@;7E)R zT}G9%9Dm-xCFU3Y%#@ z(QKy@-X7PO)QYuq&RR<2N`GDzGMLAMkNIcuHBvH1p)4k$R|vseyzZ(NjVi%2c`gQj zAqSgkmT9P?`G~u>esZJ)N!Q!ZiUTA4FiJuf0CC>6zzGMG^FS&$fN`*t7Nf179<29kG4Zw?U;*YwS6hWy>`5;PHIa| z*J;~y=MDTv%HaVw$0^|srlh`;Yb_WByW){4175R|9Y5=tlp?5|Mzy0W^nNlhkn-if z5h=u-4G1^nG@bpTfuAvbol zx9$Nx{wzEWv6PHRl&(#Sz&DgOr%$Z3HgqjnAcsODb`_SBnIZKI>#!N~H*%%zfgV4e zcFNn;3LdoK#q8t_Mg>}G;O;Bn><{>?# zy%ZtBJsKdE)h<;%TDD^e27Y8`G|71;F3kZe$oPOy(An!B4%U2eI|EQgMN@N>T_03* zG2E}VcSxe?QC~5sG5M}%F%^!Z=Vb==>!VSjMPfm+KurptpRX0a7@8VJZ<^zLkB?Cs zZNygQGlm*DNwy_*XLw#PvO65B(?}^Rgek9&Ig4bfN@0^-YK(u^SJftAq(>jjT5bW1 z_fUwWe3JKqu*jlGOfd#iOa&`Uv?>H%%g$mGO-GSpHV1zV^k77b#L)2+StzC%t&T&0?VEa1GYcou_lo zy5>hhcI`k8E+2{sH7y{|NGs=Mq{q3wyPiiBT1kRiupn>8 zX(l*oxgTCnU=S`41sCZk-+Fv6PcBCp7V{&Smi>!{_YIb@MdKB1$d2($RtL8Nt-8!obD z%N35(r0D*3oo%Jv+uNeN=C%=&d)^Jfd&3#5iz?OIB4X@SvGXSCee+i>EFU}+m^38X zsxqVqBA1xjDDflqX;cVVv~cCJ>wH0UtyDYD8QLE;%NmdSLeI4vUdhMRY(08Z7FAgboRXD-C$%%N_7(VCUX^ z$QZ-R#rjNk`KqB2)BnNBaMEhHpXEyV*rt|>ohx@~Dp`?p&8Lo@4*zZ9vrbQe6U|o7 zWGHG=8b#)m(T>I#1T2{VxF;6nD15`c7x+cw6d8YKw~A46u-~wq1lc8ssn&S`ABuUI zzQXqC8ot4lg|8z>c73Ms(vg5>09z8@u|7>O)7?V%QBQ*w+uZuwr}8WPtpUqb3bDzn zMO!#thiL3!)3L_&*E}b&_D!)I8V72gs_)fb`nIazm#AGoPT0tnNjt;#;0p$GIELewCxf%atH?ghP=|N>)KpbzW8Hi-joEgrK!A4y@75)Tz+isp_ot#2 zI&V-UMzWM%g#qKz%rDtrke{%y*Lteiwsqj`I%C7p=$3WuX|Q8lvuQV!$E7XwW8Knpmoi&oFAn1Dqco-5^ zhY%v@?aygfC7tDn4Y1xLb<&* zlCvx)bP~3nWLG1L(?9nn*Uk?18#aVmoT86%maGL9<(Ki)C0}Sbw}14;$o@X6cV+_o zljk@wbUH=YWf6>&x42}X(0D+#n zaXFgV!8o70{ag3ze}8=v8t|9uk8k3#z<-0fai!A$sg|JNOVr=*3(%it(Qe=7b)pZ^Z_`;<)Zm+p3lqj Date: Tue, 8 Sep 2020 11:30:33 +0900 Subject: [PATCH 04/16] Release version 0.15.10 Changes: - Change to use gmock package instead of gtest - Fix coding rule - Fix static analysis(TOCTOU) issue - Fix StepWgtPreparePackageDirectory - Fix extensive smoke test Change-Id: I533e96fafe2f58292c2b228b6c5d9606030a6285 Signed-off-by: Ilho Kim --- packaging/wgt-backend.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/wgt-backend.spec b/packaging/wgt-backend.spec index 3ae7328..849109b 100644 --- a/packaging/wgt-backend.spec +++ b/packaging/wgt-backend.spec @@ -1,6 +1,6 @@ Name: wgt-backend Summary: Application installer backend for WGT -Version: 0.15.9 +Version: 0.15.10 Release: 1 Group: Application Framework/Package Management License: Apache-2.0 -- 2.7.4 From 38ecf47d17de4862e5a66945fc26ee0df9d7c58b Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Mon, 7 Sep 2020 10:51:57 +0900 Subject: [PATCH 05/16] Add recovery test for ReadonlyUpdateInstall Change-Id: Ic78a29b63a26ead900a8fc2c25350f05cd5e2cb2 Signed-off-by: Ilho Kim --- test/smoke_tests/extensive_smoke_test.cc | 54 +++++++++++++++++++++ test/smoke_tests/smoke_test.cc | 27 +++++++++++ .../RecoveryMode_ForReadonlyUpdateInstall.wgt | Bin 0 -> 38755 bytes .../RecoveryMode_ForReadonlyUpdateInstall_2.wgt | Bin 0 -> 38758 bytes 4 files changed, 81 insertions(+) create mode 100644 test/smoke_tests/test_samples/smoke/RecoveryMode_ForReadonlyUpdateInstall.wgt create mode 100644 test/smoke_tests/test_samples/smoke/RecoveryMode_ForReadonlyUpdateInstall_2.wgt diff --git a/test/smoke_tests/extensive_smoke_test.cc b/test/smoke_tests/extensive_smoke_test.cc index 444fbd9..6bd46c9 100644 --- a/test/smoke_tests/extensive_smoke_test.cc +++ b/test/smoke_tests/extensive_smoke_test.cc @@ -72,6 +72,18 @@ class SmokeTest : public testing::Test { TestParameters params; }; +class PreloadSmokeTest : public testing::Test { + public: + PreloadSmokeTest() : backend(std::to_string(env->test_user.uid)), + params{PackageType::WGT, true} { + params.test_user.uid = env->test_user.uid; + params.test_user.gid = env->test_user.gid; + } + protected: + WgtBackendInterface backend; + TestParameters params; +}; + class HybridSmokeTest : public testing::Test { public: HybridSmokeTest() : backend(std::to_string(env->test_user.uid)), @@ -466,6 +478,48 @@ TEST_F(SmokeTest, MountUpdateMode_Rollback) { }); } +TEST_F(PreloadSmokeTest, RecoveryMode_ForReadonlyUpdateInstall) { + ASSERT_EQ(getuid(), 0) << "Test cannot be run by normal user"; + bf::path path_old = kSmokePackagesDirectory / + "RecoveryMode_ForReadonlyUpdateInstall.wgt"; + bf::path path_new = kSmokePackagesDirectory / + "RecoveryMode_ForReadonlyUpdateInstall_2.wgt"; + RemoveAllRecoveryFiles("/wgt-recovery", params.test_user.uid); + ASSERT_EQ(backend.InstallPreload(path_old), ci::AppInstaller::Result::OK); + std::string pkgid = "smokewgt51"; + std::string appid = "smokewgt51.RecoveryModeForReadonlyUpdateInstall"; + AddDataFiles(pkgid, params.test_user.uid); + std::string test_uid_str = std::to_string(params.test_user.uid); + std::vector args = + {"", "-i", path_new.string(), "-u", test_uid_str.c_str()}; + backend.CrashAfterEachStep(&args, [&](int step) -> bool { + if (step >= 2) { + bf::path recovery_file = FindRecoveryFile("/wgt-recovery", + params.test_user.uid); + EXTENDED_ASSERT_FALSE(recovery_file.empty()); + std::unique_ptr recovery_info = + GetRecoverFileInfo(recovery_file); + EXTENDED_ASSERT_EQ(backend.Recover(recovery_file), + ci::AppInstaller::Result::OK); + if (recovery_info->cleanup()) + params.is_readonly = false; + EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, {appid}, params)); + + std::string version = recovery_info->cleanup() ? "2\n" :"1\n"; + EXTENDED_ASSERT_TRUE(ValidateFileContentInPackage(pkgid, + "res/wgt/VERSION", version, params)); + EXTENDED_ASSERT_TRUE(ValidateDataFiles(pkgid, params.test_user.uid)); + + if (recovery_info->cleanup()) { + EXTENDED_ASSERT_EQ(backend.Uninstall(pkgid), + ci::AppInstaller::Result::OK); + AddDataFiles(pkgid, params.test_user.uid); + } + } + return true; + }, params.pkg_type); +} + } // namespace smoke_test int main(int argc, char** argv) { diff --git a/test/smoke_tests/smoke_test.cc b/test/smoke_tests/smoke_test.cc index 883f3a2..ec82d92 100644 --- a/test/smoke_tests/smoke_test.cc +++ b/test/smoke_tests/smoke_test.cc @@ -928,6 +928,33 @@ TEST_F(SmokeTest, InstallationMode_UIAppWithoutUiAppId) { ASSERT_EQ(backend.Install(path), ci::AppInstaller::Result::ERROR); } +TEST_F(PreloadSmokeTest, RecoveryMode_ForReadonlyUpdateInstall) { + ASSERT_EQ(getuid(), 0) << "Test cannot be run by normal user"; + bf::path path_old = kSmokePackagesDirectory / + "RecoveryMode_ForReadonlyUpdateInstall.wgt"; + bf::path path_new = kSmokePackagesDirectory / + "RecoveryMode_ForReadonlyUpdateInstall_2.wgt"; + RemoveAllRecoveryFiles("/wgt-recovery", params.test_user.uid); + ASSERT_EQ(backend.InstallPreload(path_old), ci::AppInstaller::Result::OK); + std::string pkgid = "smokewgt51"; + std::string appid = "smokewgt51.RecoveryModeForReadonlyUpdateInstall"; + AddDataFiles(pkgid, params.test_user.uid); + ci::Subprocess backend_crash("/usr/bin/wgt-installer-ut/smoke-test-helper"); + std::string test_uid_str = std::to_string(params.test_user.uid); + backend_crash.Run("-i", path_new.string(), "-u", test_uid_str.c_str()); + ASSERT_NE(backend_crash.Wait(), 0); + + bf::path recovery_file = FindRecoveryFile("/wgt-recovery", + params.test_user.uid); + ASSERT_FALSE(recovery_file.empty()); + ASSERT_EQ(backend.Recover(recovery_file), ci::AppInstaller::Result::OK); + ASSERT_TRUE(ValidatePackage(pkgid, {appid}, params)); + + ASSERT_TRUE(ValidateFileContentInPackage(pkgid, "res/wgt/VERSION", "1\n", + params)); + ASSERT_TRUE(ValidateDataFiles(pkgid, params.test_user.uid)); +} + } // namespace smoke_test int main(int argc, char** argv) { diff --git a/test/smoke_tests/test_samples/smoke/RecoveryMode_ForReadonlyUpdateInstall.wgt b/test/smoke_tests/test_samples/smoke/RecoveryMode_ForReadonlyUpdateInstall.wgt new file mode 100644 index 0000000000000000000000000000000000000000..bd12001d770355260be51f6b68c27e18dd4631ee GIT binary patch literal 38755 zcmb5VWmFwa&@GH>(1Uw$cXxLU1owlxyAvR|yE_C3?he6Sf;+)E9NgvdyzBn>{=DB> zw|jKW)bz~ms+sDl*{TZAFjx=>2nY}so|I}3|DS^Nxeau5u&}md_OiFLPgHS)`iedT z4nP{{Rt08pX1jN1dL0ifx=NVnN4_!?w7uQt8Z7@UJAmN;za5%aXyMw9;+xKIF`eWH zsY5CIlp1uFbUxfIFc@$(c3Axtr>6C&9DgQM^&92W$U$Q{1Wp+2X&Dr09hA_O)-^m* z%-ei(d&f#`6&J{>77@3;naFvUU$PXirCnkWZNkR2cWx<~irJ}*AWKE)x1wY3fP2p! zZXpwb>g0i`_TLCm-O6;pO&P6orb7nOB8rnpA;&Arll$em!Q8RI>KYRXE2nLlJ7t#8 zrfUem;(ClODZUB)^otVBsk@xn8s=7Ehf2fb)+Rl$SRN%^^#b-ct5?x*KNN70BE`QT z%z>NRr&`_tq}|;ly@i=?5UL9B2%TO1#3Yaq5HL^>pZotCs_>tvTHBjgn!B<<|Bu*z zh<{4_Px;@)0H4SIub7*)kGX>p2RpNqgC!&@`^;3Ns_`R#LU_uq^F z_qmL>(3*mPV0)006w~m^0r^|HVQDSdBTG)t!5rl{_dzCe{IqN6=Qg(MBXhwbx1C&nv*!7~l zwL>Vcx8;8-w&r=rhzs4D1SH=8?)4#|mCMSw^K*yFR z=NFL5HcUp;U<4W|nGmm(Pwm3sCXr2#<#L@I%MO>IgUI`CHg9`@z8lL)O++T|EL}^nB7BxI7Zb}hu3aD@Wh-#?<;1lm zGik~eefVyVOUR-3{cE>0= z^AKZLiQL?k=LeiZNcAD8?xVWI+|kSiZ0T~^ERK4AEVDAN936U1D_QWh>^IAQo4<8_ zdD~v2Y(&D<++<(4F=hu^SbC`NB*Q7G>NeXP1W8e7E6FI!i~vLm&rUv~FUkX@yM69v zyS#4-uBMsJChb2&hdtE9e%QB~3F5xDz2zS%<>*T_^jgW$2dJSdBB#V==C8|zw~G+V z9L|oC%RJ-QiDd&mLRHj1;E7es+R?13(^ZILAyrRNm~g~w2Gp*T=x zWMYA1J;GrRPdbHa76PPZ=nscY8I1(cP)7}D_-?edIn0l) z?GMMUPmoxn>Q6mljq-W;v1XPl+pIQ}CQDj{sPUKz+kieW?oi)*r zoinrBsqp&QC4CDV^CdX+JX-33BW1HP@q{#%KncoHrSB1)D5lNyCXEwQV$|B8wPx3# zqMOX$fh)GWhDM&yj#PmWo*sg3qAyktXcg^X_(i@;3W7&b+n&1yQdS;r7-(jeP?wPY zIILq$pNTwK4_rE4V?ufwW18icMl^t;ZV4jrB{*VMW_O3x}&ywxN0G7 zia@n;Phu8Ka(m5^?2j{WVB=c34fVeChYe?(WSRF90;+ zko>ST;g+W{D}4QB2j4V)2Gb5o;@v?S#g134zVmX5wCxmR)BtTHVgr?`&G)L&7cQez2Llhi~ z9viZ0o5_(6G%X7EPVF>we34ZU*YgYl;aMEoLbZO_JKD8Jw1(M(FT8@{mve4LSUc4- z+?%&2;rGAu9!$Un~SazvrYMogsGz=|+KI@tpqobiDmGi%s~yW_ZbhawYota1%wOOXeVI3J`TeAlKIHJL#17g>TJE9nh*K z8T#Fr_^-0pq$)Z6@LhU$06=>_C@N`;hQY?FfTkMbs5Du?hiW2Z^yKj@)@!P4FE~o@FM%j1rKlwJCYhrVtQu z>H-P)k{3bz!&+oNhd=)6M{aVoymcrX+Q50`J{zkkeTR}!^r5TAZufC$1)HOY?zDb{ z2Q#1J5APzN<&SJy ze()E9p8%N$P~=yM2tEcM8pVtt>xD9ttuF7M@$oX^;!sO9dJ*OmX(mtC2ilDmu{S>Z zWlAe;&J@a|E8zx&%Z2+*_Ot+JqP(B#my%@)_dck3_~dhH1NTqMYG2>!vm_@y<*h7e zOk`O55mG8L^XuKH7zr;OgQiwTzUUZYL{ zf}@Ee61UMMn9kt~{q#I{U!QJxJuiqp9npWS(YP#o17XN*eoqZuJuy{U%==&wbCZ!m zw=PaU7Qr{vuSSwlZW-$2Q%47nTQ`SBl(|y;QI^hdg3dfwnEQuXp(Keq4O8bC+*U1) zR!Ko6qc6Py^}k~N_^LOYyBXjEXb}-L5m|v*e4>A`RrI;jGE#ozlUVFpJ%7h~WkjTU z28(8@!K>PwV_;<`>?O-KfEdML+Y<1oDYei$j_Kv6_@ktAeR;cIKE0@MlkLC{ArfJ~ z<5qCb%XGc(!^Q5!W@lR<_;=%W_#iIEygh}W5lFQ1N=D7hh5$)c1~Hf6=!Qzv%tH;b zda;3!wpSdJEV5W-bfr%BAA6)L3egTHs>|pe_wtdZSRo_wgwKa=mpIIc0X1Gb6`FSq z>Do(!#AT6Ja7y*3$4qf{s5Ij24~!oGqy@7%m=6=`QPAQba$x|60&UUV>SZ$f0umehGEzgQ?`vy$uzLN;~ z{7_TbEJF*KvV|qM>WsBrbfXWW^U~KR`lha)n3{UP%XW4Tt??w!KFl0h!D+`c9=8(l ztr)gR)?}U1Wc?q2mOQ3v%d!YMiTRtkNtWI7ZUiY2nU$cSgU8dMf68$OPM!mys>yA@ zk)TwGYl6X3*c3^`RJxk+95xnqpFEQB0Zg4d1IJ|v#QjDGV^@rk|5%V^(Bo4EI9yI^7&ut+MR zN;XW&c{d_9JQ#EKzNo3L=JwO@*-eEA+)j5lXrwJpuDlpi1qcq}A>g1BYi(m>!^`jF zHIiIY2wV|{Xoy@h^vRxccs$0)gemWlkRo4k;ybD3rcpFxM-wJF0V=iakw<{W%TqX$ zl`=gq&k1|K1V4DLV(tRv1y;+9!f1WERfqPV%mg{vs4;-{^}(+O*D}7ihQ>@|#0WiW zdhG+Z`Q0%uaz6q3FI$m3&ysw0pyk?p*N+Sj z%!bsU&ECLmM`|ymf{@2zuwdw3T>pX{ejZ-a!U-1D2#E)tzEhbNs?fW(H>^~ezWd5| z&6T?!bydIW&UDO|;Tq1kx3)dtNkMJVx&q+Bi^Hml2lGG?E8U}#j+M;j9%{G-m5YaR zMB>hcM8OPeYF8)}2+#vaV~ZsH($%1r&HYq^NZ1dr)nU_xsFJZD5j#I-1x{t3SK~PO zhi*QayXc-lO2?~Syi&NDjpKGttbpeQuk`SIhW;$V-lr$>=R#m)+efiss?MDDZHih0 zuLHSM=J}t~sT_RWt7~^qnCvS(Z4h>JXVm=FvTDGSy9{c+VQ%En^5!3gGsiuY#6eH) zZSgz%Ry7HTs_ruqg7fxx>KD=iwSRt#zYW$Ql^bQLDLL=zpR<=KmY0OI`pnL;Yo}Y( zm3wAFIf70L7Jj3w;e2sR3tMptX)zr_q5+k0*w;OJ?aJdAo^b<|*4>=;u;E)g2;JvU zGe>wca&tj=0>OkqDVt3SJZewT%?O|_xKuc>=&Fe?N$TLLB|1B}2wJ=1Pc3W;_~FT98_Ynxi;cG+iws}&W99(sZ z#Jyigi8SI(&jY&J4Uj0oo7n@eb-EzP+`?k7%q+WXl?<~kZ+Gy@W_`}9VH-ySuZ`H8 zHXH_Vy1F@cx24!dl3{1>- z@6%r5@+RG>BUI6v5}LrJLA0!;g(ktllZm> zI@K_nfY~cQ)oP&@>J74S7_NbIWE%r5g^RZHkh_MCH}p*PSRXQZL~RsNPdl4JQmo#i z>c7imVoz1i2LnzlKD(9=VOxw0v={gmnuDDlN; z7M@^qq1(nA?&b56M|xcjqJUbphC|J^%S7tv))A=0E`3XDUxB7Kahq4SJAW~IQHw8A z07=v36n}7gk^UHpvq4suKxhW6a%o`p<$X?oK11cnKW9)Y>)8%_Z#AorR_jcQYtDNA zE`N{i3jIJdu1Qud1l^WeEi~4;8XESt=m9f?k6sAYOE{!pU=#_uhnP?^E0V>CJ@j#G z0%?Q}A=gN7?1gE&t%giEiAbY6a(kR|tjp?ca&G3sPhN4E*x2Tr%Q6Ghkr45KDE&n_ ziC1pEq)Rvjgfj`Ca56p6wD3u`|sTHj=u)ITB?)rbp< z^Pu!=r4kyhHCNobQmwx_0a(p4QpK9Z>PFtXvGv z9;wm2Q8X}hG+_oaNS%h5b%qM#SRUrPZ%nHd&9A&!vfL|s(Y3_XS7iuWPAdDZOgJmm zE*yJgNC`@IE)c_Eg;~UF___Fa-U)}qA`%mC53_dpFpJ%u-J+n5P=0dg=9cXNnz7c) zs}{Qxd(#Q!o&BF-6`LSJ5!LA_&z@(Kf1@V6c`kd21oz0o#{8WE`jHCrM+#-2y^aaB~h5uRS@l+MP z4YCkjBpW?SX)HsGn3G*uG;W1i&P~EV)aD{CaNrZ|X1TtMvwB`9q{6GkjZHUvv^ZDm zB5wae>V8IZem#CLj=%2=nwJvM&N9nzR>&OUmE>EXf4SNpc^g9|UFD{SV7b0MSx`K?ktx7yowSM33kxquvQL?|F;bBX#y?Ru&ubnmPd6G6;Akz_+M%<$dRmT)8FxaU zkco4{q#c%gVJ2y1t3u4fpRt1|og#LDpvGkzNRiMZP(lLKNdu1xx8n3FK&Melu_w_!AoM0Z93N3)tK5PZ2J6U+&ZC;0XhaV2)zFc^i>glp-#QF16Yi%C2%OhsLcJ*9wM9koi{IfTVb zTC#JT>En`n2EIcE1U5c?WQ|@cIoBQU;dIV!%*W@*2Y%L_(1ByZ0iqon(=I`A0AT{? z3PJ5ioh@(zX>ag1x&G*{wugSuIF_{eUT!SD*M!L;N>|4PoS`8D0ZWXJL-X<5c$F8s zn5b?5tjZq_RDJ2yHU(N-PmH{F+}tfixk3P)*k^d|GjL8wWNe4u)c>t`@``t@ABRzU zN0v-PuhXL@a5#8bG>G#=4G1*|6S+K8@&nr21D$ zru298f^kIE(sWj-o}Z@mrqRrMvC416t0t2>Zo{uWVY>79jtnYHJA{1a~yUn;GFw8m-@dRdm{jGY_VVOzSlT-F5 z7_B`#a**cw@6M8=$EY`z)V(!0R7PhATRy%xQg5Lb{61H8r)R!vsGLlSrlo?wj_(dCLS`wL4Y@(c4J5&qslFWf5+W%Fyvy5RQ?`PztllAr z`LqUJX#0gxMfa%MHP9$d|4}^xD!wF8=cgjMtel*jGCW!6m>ID?N5Ho<#4OFXC%>cV z+-Wa)V3}U`Uu8xp?7>aSg_s(oEQqvRXx68_8G=qlohCGgydc~+&2tPE)q#p5n2K`1 z?}A^fzu1GLdVgF)Y3e{VXNV#e!&D4FX$0f_j^~X?;Il;Mf1^C*z8^*l5~iq(P<4y1CMPF##2#&bX8`Inc28~8DE@3Qjxt8 z_ysZzB-|NfvwxX+_+Mwkt$L>T~!QEsz4rDm5N9@R|W&}*Uqc!s0g_F4|DzT!l(!b3M>ujh^+w}KPs8k zJwG~^ImrmGpGGDy{E)ErUjk)I_K3NjN}k{egcJn>U8x!FKKVWc5XW4_Hld91v;!?f z{-lJ|&0(U3#Hx`>JCSF$KY>1|bV{ zo^`n=@&cr^EEGJQVLTiJR)Xzv#-v^PXu{4~0ekI-ovTeqIEsq-~*l{L3ZGcQwS1l1$8oETjvsaOv2rmZdz^DdL9>i}-gwb4o9le?z9iHH@2E2# zkYWbJ{mN#}l)&;-AGInIw(GWRq7IN*n@ELzI-%)Nr2( zo*RKYAa}s9|J}&IBsdw-jMjWnOVzz^KS&!=J*^$GjIsEN4*;0PyTn^FuJ97ZJQae=jz%6$PI~pSrefBSBJVi)CxLsH`B$ZWIvyD7_tz&>SuQiW*@4a3fD2$2*qb0!)cc=#GrC*d=-*>hfjYnKT(UOD6l75i-@sj4kux8C_s&Tg@#{+iQi{XUMJe z-@}U=gvrfrTwbu%C1vFJ!l})TPs1j7)Th&vV;54qHqMe|yt?=uh%-E*y8zo%-{rl- zdmVj?o#%ugMUIA`>Z=wain1Qe9@Cn*rSptyMFREUhhES?U%)i(RZcMghoy(_@7*krX1$1 ztzKndj&ACOo*Y(E7Nxa_kYcocj!OtZf6u-JUu40}`Yb`Ric z%(~5wX%LK+J3oWM*$|`t_B>H+hwLlRC{M^bTt&cTQ(!Tb6?YQrUG`^Ttom17)16oi z+~~3uN-gaj59Faq_9lDWc`jlL?$$z5fK3?qe22c6B_tbY45bNq@cOdR#A zd%4ID?2d5KB%Wf-CTPERIlyzq>NN+MBjl;J<_Fu^VlV#hF;bakr`|h&0}l447%?W> zT85n4;meuv!%tCYYu`ze_+y=33a4ohM<|>LD9L-J!-8+Rl;}?lqv5fVh-}L$APp&t zaH6QFD5nj$<*NjbE(#mfAV+<=5-k`0-c=p9-qbN|I~ykUy~i-dW!pir{XJXNkc7dn z6Vd$Tw+sT%KDxAG!<9?=4=CN1|HqxeQIS%o%3E%~nR=aa9-%Q()_JlklsaWmmXcB{ zxl+$Z-JfZb=ojB#iNh(X(ePd?VAVw!8j{*}4^xy}Sno?{xdkg9lb$KEh`Ii~jj-a)K~B$6D&aJ5xo zFRPmx^pmalbqxNkBzI-{d1Kh3EKn&-JzTCK#WfP*<3Oe-2Z#~JS7X{RTEkxh&b|{l z?R=LO%D+h?*W5rO5j^J2H->?l(#J7wh&kW8x}9;EY(P&&_P|O0uFJD%4xMvmIxL%Z z0*1Q5>zMvHa41$YeN@IGZ6_R}QlsaVC$XmR-^N7qA zwg+2G^8z@hovr_F>EBdLY&3l-bu~vyX=jZfmdRBZsUS*n$AW^^B&lPBuM?*m_cKpqkA0po>o%M(hG$EY{nen}YU)XsZT&^%2INcdu zJD3*PqI1e9xTIOPSlth8^n^)80=m?b_a|8a$ix-DR_A5=MwR30&wXpZLyls4puEN~{(HGy2>_(w*dw0%m+2ou|2 zD_aTaq-sh)l58Mg}NriKQLjbaAlirjQ9s|1f^G> zKYdK|tO~=Y^p6<~qfIGt&asoNJYY!e{AZ zb|VEt2A~XISbDE!_>b?h1K7&zZrQYbSX}VDDqC)U&NsM97ckD%w6=XOp8BR(@LeK? zgQz-*$!|K0Q=emW)oeV!9nKJvf`d=GfdR4X^>_*$Mgh_lT0slCQMV8~kiTQHq8TAG zH7a4X@^bQ<0OE|I?k{kn$AB#d!m;y+V4@5Lw?&UD5wT?UA-8!cAeGxmxG!Y;%WgFA z$^(his)xF@60h|x;9kj}NQSKk1A&^V(PC<##eUr-XgCQ&r?M(}vidtTH)*Dp^5h()9>!-nKE;Z*rgxlt{Y+$#1sV96MYf=%P5Y{OoGn&H^YGufXMDGF zppTkAEGhaqgS1f8t@)E00tbtM42M6Px;i^6DxUhc3nuPx-Nq}%q@T!3-V2I@r1lw{0u*Z$GG-nRx5;iR!bi|N>-uI;Gr0!Q0^}konl$`W% z%y8`dGp-O_MX}s7*uNYcD5Q$oCq_v-nm_6WWfEqSTlFmb3x;6$BeNTC<_o$)M!~Fa z<*!#o`2@UZg#c8(Bn{qY%IlewAQrKn0yCGek#n(n3;|WsQOy+mI*fxCD)N%eZ(S>n z#Oxfrw7u^vCjbsGfCFS_gLF8V7smfKOwM^oG|r;vS-ml!PTNYhS>J%HTxd5*mx95d zl{6YC?9+(r( ziPI)Re?9r-|K#AvlotKC-5XGY!Yj4RGP3}f>vMY4LbL#=;2ot_-w9QBZRPORn5APc zxuB-qKN9-7>Q$8B4|JWu8};1_WeotH;_D(e4NTtX-NlfmZWCLi7e+X3JakAhFttChVbi#Z=-%n-hU$}(AEMY zX>jvBh@>o2GH4nAxu>vp;qm4~D{-r_n1e}bHaiw6pjMJR)T;_MN;Y^=YSk1Oi-fVU zv1y171xxTp5SyO;>V>*sCoQ%L6CZ^Kfy#Ud@ppes^EqqC+a^*C*p_P6hN7ls?-%Cx z;I?%?tpaVw%DLJX6Ksd;(k%zfqj>;{iDCf>c7^kyb4Debb;Vc2zMJTUKWckl#=m`` zI--nN@SmU~NnJ?Isih1t(Z1BAn{XSaNLfS?CD(_K8M*EkY1H(nVo%zBwfake zvwL7}N#rYcE~Wd5--RAXFtdO)TlxWY+a0`+yHcviPD48-)~J_MmaF-iC%*k*)8|)! zQl~%{_~S%qBF2F97C%}mE#Ez7AW!k6vW`qC#E(8|hL6tq9OfG1)B8Tm_mebp7Kw_% z(IM)Xk`ojpPTx&7kqfBHn6~ZDz#R1&QcRIR2r=I}EWWPc+35x}lGf7X4B0Yt-P0?r z4c~Wny~dELHg|wJo~u3_3jf%j+khqVKlF^9lXrB~R7LEl3H#@7HcDpG6iMIS%nJ#a z*7s{t_psU@aZ8Sb8!3suhnZmGmK06CCc_zzz}5jrc@7YeWLval_q3gd>o1j1jorg( z5UYOguB9p{@1|4Le6P~vtI9#Zg5OT*7d_KjVJ`RC{tft5!ynPAH9yU7@5|9|>-e*~ zM;!EJD@N#?)OWR>f3^b^L^h06wS5nrEgn% z7^t%hGx?5-QOB9`nU_N_mV&8Mg`#$5l-$!kmV~scE_qNU0`#p76)*gof?C1OQ5HFn zB|{!&^jCv&M-(-*2u9S+bsX7y<2t&!u*t9CkN1T6W0U63$v+IK*l5uzUQ5h=9>?_l zXfN`0B36WmF;)dh^9!oxYTbVJm}ZSWdR;sP?r!(rt-RN@>jf`s>kf#tI2zp2!X(z} z90*ODX+*48c`-=RK|%F+vfh#hSgLLoesKuGV^~JhF=n|{6@la&Mn+fuaK$Bhk#*zR zez#8MZP2d@E`KgzU0)K?D1T7^L{)S*3#hby^N!zt_Y<7R?+*3b>0dvDMdl}Czx%b< zMFbNVvxF~7!`PIlROMpEsegO6p%pefau?--Ja-?Ccytq_2@<0EQpFgQirXhYBNS{3 zrQNT?*x~~@K@%y{@BE@__74@Slro?N33&-5w)S3=!RMN$US6_~n5Ox3!!M))T&-B271^K;b4=ujve&cSpBwV%DuAZxbPU}w#aI~F(=F74td%=E6<6LmdB(T+B0PG2 zDO%arb|HzmAWb_r(s}Epz+iDGO`=tq<=gYi`y2!hpOv}u?fu3udON;v0cspw7)si? z$Gh-pvis3xA?vvTT^$yhOOy4+q}v?)zUoP)nJL=FHkqTL zF?_{UTJOyur_G%&6J3*zPQBzdPky9(M|7Bl*V-;YQT9fj`!Vwr>R@f$w2IK$ki13x z4^F!#Ja*RSOzMZd2@AG0MxPC$F)6a~D?_CX)CwWg$^;aif`$sBaVl)xHI%kBWVQAp z8&(!w67R{+Aa~XIXa7f2yOd-yRj88{(S4EDE0cn6*_m^{60J>)(8SmOO;}OjEHygD zUFQ&nf^Lws1E)!QoRa~X7}8X51oe%uSv4u*iojb5_Z?lSP8+dpfS1QwZM$V%kWT> zmZ3a-E~D(e6&%KkEYVB-nvp4~Y#oMIk>J7+)D~5Zd<9G8l-bLp_vntCuB@OIo(#hm zoa-0(>Ri2-vTK?t>9fBP7->#;O6jDcgQYKOEDju)demubW=37tCD* z&B(QrTfym;l>6=0V_yF9n7`un!Vf7dix;%~b5RGhhf;_8lMq|43Nke^zOW|4wVv(W z9e)HS{dKq#Z*|L)&Y$xPq}T3{Q>kP^kwskMa7WBK6%bn_#NEiTwXn2ET+zoZA{NE1 zocDevW_rlD8dX9(KOufoE;ye~|`dPzxK5rQh%eYB7VNF?33OD|f7c>*S z&m`pcZ|FGQ`YIjbQGiJQba>g1GykmkLV`lp3=l7M>BiUCj!u(+wK`F-S)xGt)DC4F zxSS?ONJeP2{q*hNVkTs!as%twm1m%SIi$U5H|TbP z7H$>mK+MYWH*5t@XmfXQV`fnUq(C3~ld?d3MhK^udkC)~sPn$^g6w zS=hA_q zOx6W^J!)P)Sh8;~e?jScLNXf?rJ0m31^;8JEhB?9#h;;b=FYRX%3OYFd|&G#1cR~h zZODZL#fjRaax$kf?cAGA?09h6>*YUGMe`MirqcEuclo@2>x1duZ6{uaN%3}B?iZ`H zYD0OwerQ)iWHP2Pr!h@F>YS6Bew2*)`n_|A>EZ+!TLG>@2r#m#B5wy>`km4m~CAB z6Z;(oSigjW1;hRlBVaOks&d%_=TYqxi&)UVL6g`Ih$E#`f`!ZVXusGCOWhy6_6C6E zEGF=b=Wha;s*}Ls`2}y7J4T4RmIDLeVvTaf(<| zvN}^O4hyT_IsWO>Yy|x4l&NOkuQ++Tz{l9Zvs3c50DIi&adu#Yot*FK#qu3>!qwPwO=M{kSdoT*C(?I6!EE$%~ zoU@pDDD*`I4BzQKnd|1C3mPfWx#9EAyj0nX5AGcb-ALL4ZiuBkS5x4HA0DTu3Oz&p zhc^(FsF(MX9OU``OAdnh#2e`P|HcgZk5Hs3^-Wz)MVaFt)c;V5)L+#s|GU(Gw4(pL zb5Z_pW3F!AcIM2V&Bn&}EB|5rA_;zrl4Wp!!KP$BS#FEusb5kmTAXMgd(SPghTX`> z&IipYCWMhj@U?e76KVX7&4DS-8@V!B6BWG{3rL2IDz{p!*rBg%{4%X}i+%46=X*tE zP`tqHOfQ{l$bEO$Kb>8+YwI<>bM=8wRFk>ukkU8VhQERZTU^~awvB9`*xuV?g3-`N zkl|NTpWr%G1cKQ<*lEc!Inm#C>PfH)u9lb@V49gzMEb)eQTf0$YK>Nuy-ISZuXcCL zboj^Nxu3zmK&`fI@yPK%;DeLxI_Ey0H2xF({~ZhH&oe$1{r`oLh43k2{mGB}kA?;6 zhWEpkT88&?PynYUh(rBIKo>_Q6Qbml62pKY9D<4>$1$u&rVly5#>R%-g;YaF*FaC8 zE~KDJ`SBwGj`FK0*^eKTJgot)hZh@);j2Ny&t1aX51@E+@aAUcYUW1{|51)N_`)Q# zTPVvHBIp4m0T)9y^3lIJ754g39RT8XaSHSpePe;}g4_EY3~R&#eTnyOrn|Q3DZ=Ky zwuqaT@oaYsvbLU^5f*XZOI8sY3CR&Q#{ZalRt;co5aXJ2YlE7jgDx3+pMw^x%&QZh+u@?k|< z@8XBLjO|My_X)dwTWvEho(ZiC$8X(2Z#!|yJYzEKAG%YX|4L-xgRSPv{aw~oTk*vb zuE%96C%&2|SPU1jtZyJI+_JvU7RO@^Zh}nwHnNX6Ooqw#wQ6m4`e#f-xD+roO`tP$Kprw_ikN+;N@&l8lLn zc-EOGmv3TbuDZ;C;_XP1(KY;3`dmp-v@cEEkHES;>Ce`$TPuM3k!ftIEO-CtjscbA z7aPO3lD7vmkzZBB1V=m;y3g(WLBDF$JuRBu7pA=SK#elx>$UfdsD_xx9MoIyC$11c z_@+xG!K_2(bN9}+94QVsys6% zc>SKCN!lJ3z%_x_==xK5Cv<79cLuSe{9sn41NDS+?=5kzI9yWm&f9PucrOv!;x~T= z;TAA)ebLgNE1cbakteKUNI1_OxZV9E5ZZGkc)!x5jC>f*sN;41WR&&rRJT6g0IbTt z6cTE6Tzii@!Od#-SiNx@De>=A5A0!@^WQ3t2yl1`T|V`n3hV&GZ!SI9d=lPn-2D3{ zgHJ9tZx_^yX(aDR*$=1L29;5sg!zly8$PTbE-pGeFIKUaUA7)10<9Z|dIMA%W%xa_ zge+uDtImVkgNa`abCX-jeb0g(=J`kL-?e>TX13!5F`P_iBQ2$yIx^Z^Os*3SYYyK6 zp6kn(+V3A3**Z3Zb*Q4{J<{Fi5LqHCeP)4k6m&EGwp|bU>lpAf+ZdXsT3Pz1*N^GB zFY&r9#*+OH3Np{0xi6xpS*3(BuU<3fVCduzOR;zg$A}H#+fJ@+zr5Ag$XS}xyw|IN zCZ>1Td>NGNK)c&W30!!ij6g9@|Bm#B&VEO5K1Zef%7Df1De5pK$NT+sPiC}+fMzf->LZ`8i!K#_Jz? zdOT(;m>+Oz-DW-qxfS1|FPM9IUbo~JeEmgy|CWHu$spNtCi<;Okm!%;oHT>;1dB?Kt84iPsgKQH+?!s!MxW7BUrjXT z?JavyDt2_5BWc@Rz>Q-5`wRG|FRjC6NjrYHl=;KqmR{WeP-@h`-)E^>N%wBib624i zHKS)g6C2xz`Q83JX2?_7K<)ARo?ZRV8F4j5jk+R(4V-VRvkv(08r2L#u@1P~AU}Ie zpkeU6%l4r}s7rtf)QOm{k`Z{HtHMnR?mqul@In0VWjFbSgx!k3E$1tv*|Y(RMMwI*?TPm-20Q1g?2lW)q$KasqA5q%X#QX!rtx2 zv;Edu25;l1H*CUIA&#?Pl7~PZi$!R(TGA$qxvZ7*8rzoNmqzv8D_tg4xRxqwZwt+_ zy^i|rbm!&s>dfA@Jj$z&&p+hie<-gtd4evYyw{Jqdk*eCn(v+O@^a4_`LBaVc?=&9 zo(l3F?ilqGuH2=1mmds2_Dmz>fN{^nLVruWfIEecLMqH1o+gJoa)rsdy6%5*)?70}e)p*Wu4tU!Mr~)~58fi0ZdG0lrXKITs5Bo80atGZ zhP*8=qHCGH^6?Khuggco`Sj1bvAfoTmdb0YOTPw-iG}gIsgKH)wv~*&^X%GKZLjsr zd{nhLI)g95a*@HLo^8I*WzgBEDBD8rS8X~{){ZR=A{K!|0YsXUKmRJuck?uUOu{!? z>@(C3oj+C>&2){}E*}`4eC#Goy@kGf8rzg!slf6dLFb+85nI#K@t(;?%6++f9nW6p zuP+&AKW+fRD{tXi8`Z0g(!J~8V#}i#>wvC>*WU~AN9EnBoPC@-(U4)tH0}gj`y=%F%Kl{g*F!~60G>04QO?R8LQc_2fBer2A&!yMnto|Z)K zxzoLh_E&~vC`{jgM3HAfxz{IZ*cm#e%YC`s z*g65Jh&(;EFMen9oLc8SnJ>8k7zy4E?l&&2-V5LKm!YcVcfP+bKF0^LZftJ>fv4BV z6r@(!$vYhm^ZUg#7rfV7{Uk=!h8q{7se@-|hyELHXH_2!Mu;oePWKD3+uZ_gZZD&3 zN39>M?IRsqGu=5yYD9Kc4;TK-BDe2%Z?TB#%BV*E=C`lSj&_bW;|3~IM4dM~dICIF zdGrrN2WtFhch|2u44?G1h28fe6o4X_83|1Iy7gikdM$ng-|PL${#~JTx3QdL&nmMWeDxruiobU=}CCT>nQJisPnkT==b6x>f{;ghwOS+jiaOD zdY7FH*r-*gXYV0~qWd}a)#Kk?Vp-xQy)u?vMgq|9&`avEYTYK8C4bV_NiVk<4DLOM zosa1_`}Zd~KHHI}w)U*`zWY0FtWid}V3);8%F*xh<=j~v1HC7^$<-Wp_G`)fM2bU; zRtD1Z#@->v7AdXr)`yEjq0_+s!`C@=SJFmXIJRwmv2AC^&W_PZI!4E~t&VMb$F^;o z9joJXPR{uOr|#;i#;7sgRkh}t^I5$+?zPK}kcQ0d+NXv<+~e(s$7s@?w?UoNDI69l zrKn3*K3B2jATh)n10%oNMA%j&k*#Nsr;-6J#^49t7r&gX_kU?O7-YtWqIijfFmAX5I?KjpjA+Jc2|8A@>92QjmDATB!WI!hR zyf}jvc_QLDUTBi;)Bl5U(5~bB*@8N2)J$yU7&4EyB@BgYBA@qK9 zK;nzgqSedZ{L9`zQB|g&aCTIO1I2DSheWHveDl`su(nM9PhOTL>$_<$tleu_?MW{m zpYPl6^TXHR3w`r$-=!znY5iT!!L7Oz60g zJS`G75)%Af#)3MzNsb?rhw`Ud(|N5wC%#2umXfsa&-7ON)t>TQKmQ8(vWC?gjvwoM zLjGPy%VvO{L3zVyzs8!+$hSP3YoV3_K^EH`!A`?xv*zP@=BtN@9{kU<1ax=sE(}E0 zL%RSk0Y1b3_^qS^*( z#XD2FE}+cVl8#@~gdh{rt7zd*M{Y%YC5UZl4CEb%{J?`syl#3KS3@U4C zGX1Hfq*MY?uTfzBE|Q}5m6%V@h#k1}e74>g8y`Qb4Wa4Zy_0Zud~9|5bPwZ%A}Az8 zE85)LjFs^A=G8%|4TaS4AbJmW@%Q`YrM9+qW_xfj*s!j$Hf$qP*Q>g+l0C`7Oou6z zc(qo;&v~y8yx25a{I2DTbSbM*)A!qM7Mv9ts>s&XhUDz(7>juOya)va6_A#OTT+~v zNzkE{gd)A?AW^;{)M;N0%d zwFZBVXv{;suDi4LaSX*Bb<>A_*ap;ysAz z(!i-~c)<_DY&=AMu6}U5dfyVMIjE?hLBGiXp!K^v-~oN`KMl6aHe2oW{^dbElY-Na zn!~31Dy{ApTxJiIjm z=~HLB?(gr%GBTY#on+p-1NwH~b=&E+`qc%zw}OtpoK>))$L3h5N?;2nPzAfYeiu zW0n|G;%iCCDSVqocto2Ao9}4cC*1XJiOOeQ;DolFzP`R_)k@7NI+dyEcRZ}QCnVOO z%^`5Cv`UFpn}$O4Qs8Gh5+@9EQsAW^WP*_Vicv%N2bpM%PVzV$(QF*xy03QMd(U3g zB_uSoKsYK@SSTLWV^e8V9d$ zkon0yDmgloAC~TYjs=~3Lu81*FC^>}&N_>BBh$BAzq{{g+Dw~v$MKh<`3gmtg&E9F zfkNBXja6@amn|#%K0Re5q!MnzXW*P%W7&I;kTC!AVmy>_$jx^mq zJba}@6j{{gCI5Rnee=76j>I@h{k`zTQMevwzul2?LO*Y*ivOD{+d@kr7o>#SEy3;< z-B&1d!KsLrAV3qi-%^lI*=jTH9*h&X6yUh|Y_!#ptwskjny>9%9}(2Dc1pFHnQ9zH z#d1U53}Mw)^03>O}4Cuu0(q;I}N6NN&hku7DTuXOf^q@k9Mq`>i*XC ziGOK<%VAM`aXZ@az`#PgQk@_iou1CmPnQSqsK3k)uMyX2MD0+nWK=^osLut?(vB@1 zyVWE6{#Gm7j)D}u({R*YPX-TuZd5W420RiqxT9a0=4w2EG?$V+Ii$@wirC%X9<3rG zBgyR+kYnPN*A5O2*ps)^@3g?Gz8Jt1Wn|ze@_&(6Q^9vLgoZ*t9y=1ms20MJ)Qz(f zqJkeO;^kuCy-S$E-H0J@6K>^G|7ByPd4wQ#qh2Uk0WbZQk1K$O>F8SJB)gHH#9TZ@ zmV@`~d8GM*mVz&W4CXgX|AdyRA08e89|_x)H&eP!xShVp?%yZBnCsvCap%_7)&k0L z=Cgu>C4Q?I9v>a?2JY*ivEXJ*ncAkg;@FEDogTWcjKAO?(-eU@OA2D4c!GEN_`v16 z?R8GovO++mBhkQCkNNRc0)N(Z#iTWubMpeMlQVRxW7)%D-wnjXz)Q4q4D%$*-4OYB z_I69OKYNR?Lc_zoM~9lW&@eEz`UeMd;sjyPSP0S4dgg5HvcK)|KLQCYu+Tnz&38yseU1&kG2QwCu9f~HU_Q!ws#}lC84%h zH{x|ZL6XEI4zZOzx`3h3O)#nYSAAdn*%*LrFJ|x=K^(?1viaL5*i*ED zt&P${aBRwDPas{DGm}v%AY3sN(qM$I?>_-9omKX&JG$L+8kGbK__Xw|5tT;(I-a$z0&LK=ZDYY z+!H-LeMjJe2dhr-Ey0Co&mEFw#_K@oPWgzy0o5Aj7NH>5k-J+KrYMpiXf4s&4meqI zn!QSNnrNug1PK}UH3Ng+DB}5pqxT_L>`2hosJ^A%8vuy$XMXQ&qcqM}5?9D=O8)oR z+voR>qwoBSEPqKoIhEU}GCX{g_wo19=`oi{Ud&b0Q`sd!-G6r*|4@txuCQ|V`xir|R_U8OYqSRSd9 zlbE?d09fIhT#484(G%J2eSt6Fean#{v`TkSX^wh~3(B}$9P*V#UX!NuC}`XfU!`zR z0xHJe{jT*xsIaK8La}MmQNlSKtZJNvHhsNJc{gUe(+U`R%mRzOE(!!D*F{%N7LG;0 zwJt0yNU_wJZ$@&kbam~|M)%sNSaLd4UlfI)Zi?NQKw?5z+Y?PiBSlqW5rmr9T?QBO z&`s2haog)i(b;B{u_np^2(_~LO!gvMm~PAtVXHTp_E?6 z)uq79ef~}QF!saEl)rfr%16L44Y}m{jK4+iu;0_u69f-xeCK;vsZg~{x__Qp;uXd} zlKj;_yD0V~rDDj6$@o4VksD{HTt?i9OwLjqomh0sa%dgJs8qD*sq(^l@X#AgFZw3W zbVzGTI(2(K^)^J=c#tbiD7B2vnCyU9o`SWHay(D+OiFe~NJ&gq%G$bab?U#-=A-r$o}Ytndd8hhg+-^KAz>k)0M;IL$&9himm#T0gcO1*3DG-Y zcl#gVJP{v@g?F`%T@A=YwrerH!%4b|l*17avH>GLh_Q>$h-y*48??DlM&ErieCcLd z4{j0*6ElZ<`vufZRq+MESqJ+2D@Sv+2^p8||9z=9IccM?fS(BU;SDMgvU*8vh{RKp2D=P$oXEv>S>nBT*AHk#c^ zZB+Z|<@@_)oQr>?mylI?=9+pz+K5bI8C@$urGIsHolN@GnJ*rMVS+K~Hj!2D+Uds| zcBfwMc0LD4RJ{b}v(vjeyT9jqYNxjp7azg!(T6$It4<+#v#LeT6hNxGbDTniT5w3s5mzh#jI9k>%+RIF7$6+R_A#T=AJrr zF<>9I4-5_>{~dWl9bf%-lxcld(PNd>w2Q~0TxUvs=uv6X$C^idgKknS%USIimD)f& zl3Blahp$TRXN33!c0*xOx56*#N>GCGxzZm+S06{m)5(4;1q+ttU2>^)Q!Ho5Hb5*u zC_r3+Ai{w#=yu@wc+Wea_Hp((y~VV5a*Zrq`MFmwgwe9>A&QM+q6N7&zGu5{96oeU z2}aW*Vdj^*=mv-ehunP;1*0B(6*d;VhYI#J`A;*vEbY|pQ%z0kMnU;YY1(a>2T&5? zWr%=)09CA(3)myY{>-$_#ib5@&4?`J&ZZeYg?)Js-rj@n-hdJ>%hp}funrN$t)YC( z>1qi!`HSKWjg3}=!l)a5dt_l%Pn8w}bLM-D<)UnhxIbUhhulw&tDTDkK_i8C;JxQ+ z-ePo{o?HKr4u-p?rH$y^Xket55`Sp#d6BT30CQ0xrYZ_!6sX1Gpm>37(3uUkx;i)B(PCsfU^+oF0o-HL1&fEfEe%Dv^Z)`O@C^NC zl~mg@Mm(XYRhh=act2Q!E=E?H^G1i6bCh4qVT5bUb+>n**c@jrOLDR?;-1$lLBW;+ zlqu7I_V9$>lWPd`V3KN6>9|0Szg`2>Nc^zs>xZl8AJKy)~tfT@N#(IqYS)-r{Sxnuc9_P&J;?jk?WT1 zSvW=8kdP4h3+18G>V{Vfn8ZT+BJd&c#36{CfyH5s2umfIO)EVVpe2zBf#!gt2m3 zD0hU{4h7ZpOCD!o%Wslm#=)Qc#0WwCWZ$k`O&q?_p6Fb{3@56Sn0tRnvA@sHkVPpj z<>9zf_~`QdMPXwrUUONI+%b-W)Qt{J0Xs)8Bo6ynkDD*lk4@MMC}L((QpjDwfwSrW zoXBeY9AvDynpalOc{=f&+&$7W6m!$pAve$;xKIo%I|A6>`~U&zr&{%mBc;CKZLCDF zRT_Wj7UtlbMoERO2oC8NVV@xiXTQCM+>epTMM`wX-^R3%8p`~8>-l>|7W`0oWdq;F zU4bkq3?aEoKfkEht1i$0#o=89(Lml9Fs8$qJhonUnzh)OcWbqiPk*KtsTQXSQU;+k z^jfzu1;VDBM@(U!8PDa?#!{Z26nt2axTs;qN_}S{1Xjf3Ij;vPsh1!8+IVO0P#O&I zD>$DbMGe6fOpXTg)|~)a|5WKs>JTnu@%Iy6xDet&R6RZn zEmqQjHkCIA?v~9Mj%c<@#yJHGXUtFUw)dXT1EYZE?Zq^-$r40^k7fzOnglTk7SUt1 zZsAzPrfYOW6E1pjf#L_AYc%v^NgPnebhHpNaob4cLqbPN7#%Btb7mxs!biM!gd~BKX+9+?~ zB|&(UqO(F10gWp^okpa{FDTYdnri4aAs$kFH7UL??g^dJZ0=(?v2{7#Omg1;OhFMv zn&0)us@eUgG`~;Xid2xEOJB5eX_rx&qI0BG_{Yp{u(bf_hhc4fjr*pNhZ&F&nB6Vc zzm)Wh)awNHmRcRyqB?!HD<$2ACpIgvU`BR-I@cWa?ElY3xccRah|`8x#&;U7xI58A zk~XSvD7ZXe6;9#0qcjlEI7{L#0>5*(3)LCjx#%_=fr{fngNg4EUxmmud@VJM)3z>? z`)SSZayBPbwm7={dwxLRYTbg1DfL++>LDS9D*7pH>|VvVPl{}ExXoAr-jsvw zM{+Gu10_Q`D!+RbJ>sDnvNxa1S~;2`nB}B@r^IR{+B}`%a<&IfJv9f4RJ=gfq&D3} z7Z7Gm$I@&=v{4%@$AxU2Q6l0o>>f06BOK6y>7BD*GFCH`LH1PZ z>e_6&*E!<)XMyT^ERm8X9cL=3CXSZ+XK)Y%7oOBWql&O$cze$+$(G|zJnHe$G$|Y4 z#}w1C4#I`cl2?X$0IHIWg9N`IYcz=!q7WkkUB1T;V`F2=YYN06oQmHTy_eb1GfEp8 z&@4>bVg%NZBKElTDp4+A)@2-k7&+{j#R!aoK#XRBeL>Db6%r%UZ5UF2IB#oiC?sNU zi5|2f&7I3ZJWG)uq_N>;r`mqHO1pTlzWzJr2b5SZs0eLNeHHK7#B$e6V9O>GeSy<k)(M)d7Uuzr6?sUfh+P;Lf$Yw7j zx9iC6meA&B<|IemH+|dH{faR+IatCh)9%?Z1V)SOXy6E(M9w5Avhxo}#mVFE!Ipo0 zFm`mlWWbw$aOfe6jE;<`c}`el-YFrhq<8RRB9Xe`4z=3Je-QcnH|mW?1mCI<*jmQk8;rOe<~c(2m%kJa|1-h7y5xuwwYRtT#p{ocAe#cV z@{3W4oZHM1=1;gNR?0nC3xh^%bixB7ED6*KDW6icO!XW{*-;cqEc()&(PBp3gDYq! z_YKH%0zhdEjwk*552g;cl2TG?E0a>?aP%x%Yv{Yj-RYUJ-tBV5V6o30%lVKlR z!|JJAp)6t4yg)*JCY7F66vU8#gFNz1c2uX0Shbj+ioqXC6DfI8wy9~YyjC9ExR-qI z1=o-04&8pCErdx)uJiLiZ;PlhyeRs&l0PvRPF%4qEUzz2sFg}pi|)piUA!67SjbW} zP5a*50n9BNC7J~ECeA?TrtlUp2?wmRw-~6&WqBjv7Y6OIXq%Z_TPTW$b`ZSjhu+zu zq&-G7K>|4a=C=xr`n>HRohU9U?$xB8_L6Prk z#_VzZiKgV@ja3Or@oUb35WLzhUn&Q5A@9_u;)2vP>K@R!EYlvPoPcT>ZCCl^>UU#W?YIV$>lE(D9vFDm40{c^~bQtibxH5qZm(o_`^qj5Fk@!Mv(NIC?h zSF8-G4)<}v)GbL6#j$Etv5+{Fiq%NAUnfQv+(fnp;lZD}e3pppeSe4Sjd&49b`i)8uBsdGkYJ(pmAr&Kiav!&P6`eRR9~Xh>KE{ zQt<*#Tgt+aW;Sf*H>tqWX7&hM5`>&20bWIB{BqFE zWdtK`1$;%EDqasyOBK`nZ%hn~UwGAUv>-v3+3}zm59ZKka@sR>DP}Ykcl1J#UkDhB ziJSq|J&z4+$juwBB=&WnWiUR41cX%{dBdK40=>>t?o`z<4adXIf2Fr~_+TIQcZRl| zlFZ>9Cq+$%MRK0rfHr6K4-?``R(Yx2UwGnKf3C6 zIPf@$)%Kq?gN^@`o)*-<2tHnIrcKBa?fVRxVlk|6pD&i79-W+sdwF#%qQ=VMTdy2E zUDWleoewG{3h-C+V6~eTWUu*&cN?&Tbl5GJQI8V_xUc6(oiXXT9A^*F!kZXW>%xn znHKss<}-ib!$GLRI3yJdi2g%J5Jb70p;9X~IwW{?e2hPCT4~D-U7OC-dEDkN@_|gpF*d9eHYJ}Xw_-lR{81~uzPW~BG<6kaQmJsK5mlTeyBI4ZXMh^_ z+ua$I5Oqhik>Y_mVR-rSjqRQT4OKYpE| zMmwR?ObbsGz@*nwJZsUy!%?FAa14^OGj-Yy`G(v2b$XG}9u zh;j~&aYgAHvY7vTo8gJ#@0g=*Xi|2FUeTb}`b%kAn^Arfi|a1`!23XeiiT$Jo5Y%< zTdAw#zMkDQrUqDH?18keQe(Dh^=98?iGw6oZ^Q>g;p%>q<)A*+2 zXV&WSMMhC@soZ@Txmf`GEja~DHL{>6eMqt4oATF#JvDDwM=6D=p~FTPQ#Wq=R{m=2 z3C}mCDhvW8smgif@v|d(lLpY5mQLZ z`v!eq;%-UDw%RoL3&8>t(omSwWYzT4UKTHbV-!zAD7cEzr2*JE>^?cZoX+)X$SCZ7 z7!ome7%A*JW`y(3Ll#oECyDG#e+Fh3&Ln@-RTmsU@j#LgVkLJXf&>7;h89Ij8)H&- zN5U>(mvBQZl+g}Qu{zb9jf(PfweWJbK<_lGPLt7kcrO@M2LAD##RkpTswSqcu5N4` z@5YB0l$U3f@$)74ly2KM5?b+ePfD-Wp$RKc3V$|*(wNTgY2HM?Wj0oWhb!v*>QtW<$9(Z>?5vRSRIR?$e}A~NNseZmF# zC)a$loa(;|nbh%t8CS9-`h4<(VXFIJux;~(LW~;nJ~}!}zP?5h6G(&9G--OHF~fn$ z6A!q2fXk?GY}A>q9${pi$i;q()goW9G*!MVURACVIzEipHGB2z2;*mR*rnasTmkDh zaz{o{vBYfeMFj^6F$ed|)+jO2WSlT{JRA}{h0zvP6G{5{;Ja@BF%rdzy#!99Qx@Uu zuy`Mhp`U)fFlInX#~yg1P&(^I003t(Y0K9C*}cpa&{{REj?1z%13h{~i>jS)1x|m> ziJcd)?1#6+2bbU!&Fj=gPdl3C7pBJU8Jl)P(3b$SAU%)^4xDkpy0)_dE$r~2>G;|i zTyAz^`Jv|wv4;bBI}-1;Kg0N`e4*_0izPWjzZqhpvqgF7ic^#+`;tN}cHfw*`tJ#` z^?TuWoN_cS`L~chJn@;n6+-m1SJ6t0KPD`M69h0_rG>qg0wa|1C5MzqvB75EPa~o# zj7}~+(>u0HfkXIKhv{6oI@l!`+=m;HBytNp`pUPjl5-~U(G2Dx8H>U<9_)uUtBpRXv zyTI=}PBfjeu@$q)>;_q!W;%h+=`dpkZXvTcZtqYJ%%qCKbLN$k;~!80Fmy%Mv&yWs z>e!d?ByiALI!xJK4h=ue={(tzpr@!Q7-B=1G*=<@d4i-Y!iP?B=Q#K<)DDBmnAqST ze7Ey+w|=(pLR145rKWO!_A%==jlKR;=#)&O=q)HRdAZ%ceV7#yP#5+HMdGq46>G#U zLaQeA|3Eh+2%LD|7dUTLmIILCELa2Zb_6OYr=6RkUwa4-% z4onfi6qkcP_{Kl0q!s5JSh@#Tw;CjThmt1`Z@H6o3(-fO$u6pdS|B^Th=VtO{|cw@ zCev^596TmK)~6&pSNOYEMmf^ki87GoDb|X!KgY2`s)iBNw;Y<~1WLDb0ii%v*u@57 zP0oU5dBFo1Q-;MGmV69lO*X&b8&+McAQ@ZSD(ER^YNGP9W^qsXq?!-@0IhnFOS+2S z?Xvs*ZDi;<@(I|t7UU2Cfe>+Bj9S{`Z{!J68|HP89FZCyAtMN40W`t=VWffBfW4?O z_KJuEWK4G`t?*ITvEpxL=g{|sppaKo>AA9z`IQA{ut5{l3}Dq33?l2B#MKS;k}yr6 zNz~a{*s|Ebn_JK(#ZM??K%FhX4;D6-La%18pq+hrQp^)3rdCK7y%`1%0I5t{i3M8D z!*l+sotqj&<}5ITq9r8iH3^CN5w&+XZDEX7uw@lYVQeJ8a<;^dB{xa&N54!FTq8Al z11R27ei{MYLcp58+i+hN+vD3+^L^Cw2Q@3hbE;Hil{l6_gg&+{92x}?7Pc*u!YBPzkGbS$s zy>Z!tY?*x{ePpWe&hn+GmB#e+WH19XsRDRxxSzP-%=uBq!+Wp#A9WA`O#*nA`80tp zM;cRVU!y4$l!cL`$~t1 zsa9Fx9ND7uH5z1E^JxR?h?_$gs{-3v=9ws68%P z-_{X;UPRutMPA=bnv5ysvD*VyerF9HSTJo5r-6Qf{P3rs@L6Vha5&ejS^Hc@6eaX(jQ;&u+Lc?jS=%rhu*?YdF!Cs~2CzeQdHm`Jmk&@djgDjjywe^`7uqZsiS zOVsJQ>|=w!UvzKS>k_M}3$zuYW+jd_oP4<5ux6qumJgn%vv|~tNbCTn!DAHjA^Ek^ zwIBR><-;~%q<$~tc34gj^D<@qjuUT3f;@@K6@A33W?8(B6jOO3yBQjNFc;1BPe%8T z8kLoN5WZJ)ZIVo@7frfIN&;SQn|l*nklApgGQSJ~dBa^AAPfNzz;jtYtgAD*%L1k< zXhgI*gDKVEs4h+`D!N*eobvY-WJuSP8KT*Y;foNexIjxJ_UKK3Kh>`QDE4;r&|C_ zgpQ-}=n(WRhcF_3Z z;Gj53@#$xciEBzJ&>>?{_tEAa7-v+}1<(ltM)oY2m?erp;S5S7SnDj2)P3yvrcVvg zr*J`2aLi;uq`*FZKJSJLT(<>-jE7ZGR&`yWJH<}()mkdUlI2o#y=0);77vI+LTYsi z{-e$9+T5T{BUjfuP-ohkDj36OlGOj$fCByIoSPWCg7Zd?yYM=pi9+~$CHfPa}& z$HUxBHt0mfN~Y6i&0?fXBj{`n>s_?aVMG=)*|PoSKzf3!7&~s>`+`IWR}Ke@*-U6< zkq4yD7_RVU5@Al*-U10i>lX%06)>L^q2mq%a9plKhTQo$IlH6nms|2&2v3^$sUdXO zy1|Khv+p+PiJs8vBcTBU*&{rBrW7v9GZ|t8cSx#mZ4Oa7MjQ>!usi6|-)MT11X0iJBc3Q>qhO}R7 z7k{0*Nvv1lSkZ9o*swzM=a(S9Z^y{3bL9E|^IUVMfK>tv@nPgPAp@;WkLZ*e`V1PK zSI_minuOUvPLBA$&>454_THmz{7c(cSFsEb=U@AX>N;7|sj*j#xz5#lvHwmgg z)f3$rC-k|Smy&;i^FdE2WFttp|GfSq_cl%T3BkO3Il;^b}g1r`2*i-p+gU8kE;&m54Q) z5LJDE8i(jx()SbOG2#kMpen+Nx#Z(``qhTBi2d;wiZ*E7wYtonT=X}}LKdS@A1&-u zbOn!qaMskGT&)3Z4-yv+X(so7^37@E^hbCW@kAjpSA^s%JcvO79BqBGYWs|xZr}&T^qG^b?%UxFm?3R0AJF5od!G(G(bxbKhANHf6$nW%e*oA zuO`GR0<#iC{(1=y1SFydOekOAc{Kvdtl@dLcF>=E8R}59) zf^0Zaax6un&=>{9(1l=gC156!ct$Q?9l6Do-BO(-pRq+uNgT4CK>C%CNee-`YRPO4 z)V~tKH_|uMAMD1WG+cl@B?99+YM?dT$* zkb1Es+j@Hik`q7e)QQV|Pg?%GT*JLrFHWK2G}RJ68twl{ zEmJHbET`{doMG|De7SvH4t>T%uXP)Gt|MBa@t77XIrJAH?TT0hcg+Fii5tCo16-rw zW&{CI3SgR3IYpILiQOn4pI_od_uY0-Y_HLqZ_OmBABTXcL7fZPi&eSbRPqnVoks`o zSCa{<_UKcv1TXbdlQyO0^X2YvQsM94_CEXppK%_?9G(WE?DVHv&4j2`w}ztirnDLz zq%$c+n}mY7KEIsg31=N2X=F(C)pCA(g7ltRT?=H|4?;`CqDw)?1E`!938VRtfsFq& z-P1ga*Wws6an$~;%D2IMYqOanSW$V+C=;%^9GZbom$C`dLE}-L4Pw)EzJo_S1IAAA z!~!iyz*M&R$`?{}Uk=YcTk2?2KpJ3W9r)Ohe#P`tf)N~#aPM_#6j@YUBBdV2q5Wn~ z<>yGLV{+Qh6k)}XiEg+roBg`71K2<@d#ss$6SC)#SVB6p!u1f~CU6K`@84oxz4~WV zYq_~X|Dr%&(eB>~)v|y%bsrjcu8E37KAWNDSu>N!Zb*EWMs(6Xa5c9W*wdV&T+|A<$-FLu)oI0|=_3Z=tDV$v0TjJ8glat4M?Ibnpi zVmC6yrvW*C0N%%P%F;hcXJ|SsF8xwCHqm8kx!auR-a96$w(LE6r($G#$(?UQAq9iY2drGeL&^Sw`-m@fBS7^3A4+MbFu=w)4^uQ|eQc?5IrB=o5=l)#z%H0F+~7P#&+ z39Yv+NtmUk((*_1Pak&B6`@c8QnGahpqQmZ!rbF#$h&c}Z*dnHUi&Qh~ z)g_OUQ2P(ZC1yx>5e*A{FAB-g7{tqhR)oxQOdT)+=@h!Cujk03CR8hp>>@|1k+sMs&Q+Ov2>7$|vDv zD(2-QWM(*ZC+|=1$!_+oC;Q)-1HBlM<+>FlcYq11j|8ujZVe7NERZh?e-6aYt0%al zhs`o9FMASHl>_w@I!Eq*gO}~o;&R3+;ExI+lyGCMmhLJ_;o{+mbFNJIytpm?qUV_h zgcHJ#fao6~aj4|j?hO+>H$jiK+ay6@LK|byYh!dnbn<(QFh??7er;DSY2?rFZw@v}F zh0t$_!R!8^JQa&8QdBF5?fh2gdIer;zR_&3}ZxN?HFW+zf5+ zR9=9TV|p3G<24h*9$B&IZ*76dDZHd(AdbVSGF_3t~1cm6wM&y`kv8V z59DYVmmAHP+tOj}X8$Jkp7Ddy*m^xi5F{jRdU-+xQv^c?i`hn(B}>!}dD9Oe+td8> z)@3x_J>g2|RdeFD0)+AxBAt9N+&d%AjB`@*A)sef^wbx*3O*sV)O&3lu|SV3t#O=E z)p7&_!Q@tOoAE|)<4({t5@dpb)_vc_ninlIU4Dke*=ovhU}fOi5>^4DSzarQrQl6ziNi1ub>sn%3{6=ualTUp zKH-Anw4=21u6TK)XVy7mv2{*F^DK={CGjnS;bN2=8qYWW7v0#8I~rrBsXb`KCE;g< zZ|Mt3?sLvqZzDvEEtLX&h)x;3EG6=@2F{B_or(#CY#!HEsuRaTSz&ok&zGcY5>Zs$ zi@ms>Eas;Y(=(?3J66@{ld` zYU7`b;XEl!3b?%C#`m@nM`Bg}1yk8Z3MwNy0^ttSV@AYJED5g6iL!mdSuBp0DAta* zTOyd^0tOYul}XUA7mXil4 zU`!{kQ}~YUhlwzWZ(`*R5LQhuqN8PpO}x7fDqv`krYwSXx%Tl$7_x@pbQ^zw22_51{A zt>{^`MN~WP{rY16dA8?BfX%X23%!OS@c(xT{uv)s z`N7s91N_F+`b3U5qG=sb#V+1XI&a5_15$nzv+7(|>CXSrE79i~?I4J-MqG&sRyJ-G z!Av@KEZoov)mp zomfRqvuR^btu9TBx;MZXppT}+7!IGxC>)!SkaX)wPD*Ngt}C7K$0{dUR&&6_#FWOw zJTqIsckId;SN>K7iV5WHCQ3Du5(|mx^bn<{p~uTo65K@qoSV;$AdqGNWzdfK7oouG z_p`@-V|%`Xfj{Fjz80l6*PhTPD?WdsE2dj?TQAY6R}S&x9zD~HHJ+fe_Nw+3vYt|+!cjPXSN-*L*fkEsj}Jbs(k z&h<-ws&b6bC}!rh@A)rpA<#Gk;O``iPN&O+r~7!zx!j@``Qs!v5-S4`u%-Ir$Cur= z(}50J=3=)5?6VgI80dxXJ<_fx0@@Y>yH;d&m7=Ha49{E?pSCL>>1gj)iC&U*5 zRT>OTc>n+71N|=u%j%b@nFq6_i=C~j+N9DTD_Ykx15RER!7rjqnXWiEloT}S)pc$? z+tH|2mL3us6g2q#Xi^RV0Rd2lmyf4*Z?CY}Bf@jt=gS_|+N#2E4<m6GOS)&X5kz8fDlT2H!~k8N|d@;}4}UPE|~) zz66lu;6$>Zs7I&69?4Io;>|MJ$w6$8wCWxe5$ROj-3b&P5USZXuhINL4qXeN#$`CY=>G#Rp9e9GXHxZYa?UoIBLCQR`t3~Lo|6A7pw^3( zY~jezJ5fIi@uQqt_0OXOVOK^}*QIcG?0e5Y$gokz57qTJ_;44_SOA_n*T9Tp8LJ z3gzPG{-f?^l|rBArw8em)BYYYzy7bfLCPV-#Am=V%+1D(=kD+f&Ty{i7rH$_C5Y8B zcmZ+e4B_ifO+PI?OQdp#3kI~oS5}`*vAh3(FX;hS;r@}tt&a8kz%Fq@Dsq1pO!&

AUpoO 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 literal 0 HcmV?d00001 diff --git a/test/smoke_tests/test_samples/smoke/RecoveryMode_ForReadonlyUpdateInstall_2.wgt b/test/smoke_tests/test_samples/smoke/RecoveryMode_ForReadonlyUpdateInstall_2.wgt new file mode 100644 index 0000000000000000000000000000000000000000..508667ea400caa3717eb8ec2c5f4cd5a644b1375 GIT binary patch literal 38758 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 E59ThxvH$=8 literal 0 HcmV?d00001 -- 2.7.4 From 1f9a8581287b59a6441e1578afc0939364c4c29b Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Fri, 18 Sep 2020 14:05:40 +0900 Subject: [PATCH 06/16] Change WgtAppQueryInterface's logic of clearing tmp path Extracting function can be override by child class, So the clearing function should be overridable function - Requires: [app-installers] https://review.tizen.org/gerrit/#/c/platform/core/appfw/app-installers/+/244388/ Change-Id: I45542eeaee653912cc1661fd6a0511a87ce7d020 Signed-off-by: Ilho Kim --- src/wgt/utils/wgt_app_query_interface.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wgt/utils/wgt_app_query_interface.cc b/src/wgt/utils/wgt_app_query_interface.cc index d785f90..3c6772f 100644 --- a/src/wgt/utils/wgt_app_query_interface.cc +++ b/src/wgt/utils/wgt_app_query_interface.cc @@ -71,7 +71,7 @@ std::string WgtAppQueryInterface::GetPkgIdFromPath( new parser::ManifestParser(std::move(registry))); bf::path config_path = tmp_path / GetManifestFileName(); if (!parser->ParseManifest(config_path)) { - ci::RemoveAll(tmp_path); + ClearTemporaryFile(tmp_path); return {}; } auto info = std::static_pointer_cast( @@ -83,12 +83,12 @@ std::string WgtAppQueryInterface::GetPkgIdFromPath( wgt::application_widget_keys::kTizenAddonKey)); if (!info && !info_addon) { - ci::RemoveAll(tmp_path); + ClearTemporaryFile(tmp_path); return {}; } std::string pkg_id = !info ? info_addon->package() : info->package(); - ci::RemoveAll(tmp_path); + ClearTemporaryFile(tmp_path); return pkg_id; } -- 2.7.4 From 467543bd672dca14cb47f5e6ac96f323a3b67e5e Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Fri, 25 Sep 2020 16:46:55 +0900 Subject: [PATCH 07/16] Fix memory leak The value created by LoadXmlDocument should be freed using xmlFreeDoc member variables wgt_doc_ and tpk_doc_ are used in function process() so remove that from member variables and that will be freed using unique_ptr Change-Id: I477a1e2677f30773efaacb058bde1a5c56b688d0 Signed-off-by: Ilho Kim --- src/hybrid/step/pkgmgr/step_merge_xml.cc | 46 +++++++++++++++++--------------- src/hybrid/step/pkgmgr/step_merge_xml.h | 10 +++---- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/hybrid/step/pkgmgr/step_merge_xml.cc b/src/hybrid/step/pkgmgr/step_merge_xml.cc index 529545c..8b6fbb3 100644 --- a/src/hybrid/step/pkgmgr/step_merge_xml.cc +++ b/src/hybrid/step/pkgmgr/step_merge_xml.cc @@ -54,24 +54,17 @@ const char kXmlXPrivilegeExpr[] = "//*[local-name()='privilege']"; namespace hybrid { namespace pkgmgr { -bool StepMergeXml::LoadXmlDocument(const bf::path& wgt_xml_path, - const bf::path& tpk_xml_path) { +xmlDocPtr StepMergeXml::LoadXmlDocument(const bf::path& xml_path) { // trim blanks int keep_blanks = xmlKeepBlanksDefault(0); - wgt_doc_ = xmlParseFile(wgt_xml_path.string().c_str()); - if (!wgt_doc_) { - LOG(ERROR) << "Failed to parse file: " << wgt_xml_path; + xmlDocPtr doc_ptr = xmlParseFile(xml_path.string().c_str()); + if (!doc_ptr) { + LOG(ERROR) << "Failed to parse file: " << xml_path; xmlKeepBlanksDefault(keep_blanks); - return false; - } - tpk_doc_ = xmlParseFile(tpk_xml_path.string().c_str()); - if (!tpk_doc_) { - LOG(ERROR) << "Failed to parse file: " << tpk_xml_path; - xmlKeepBlanksDefault(keep_blanks); - return false; + return nullptr; } xmlKeepBlanksDefault(keep_blanks); - return true; + return doc_ptr; } xmlNodePtr StepMergeXml::GetXmlNode(const xmlDocPtr doc, @@ -127,8 +120,8 @@ void StepMergeXml::SetXmlNodeAttribute(xmlNodePtr node, reinterpret_cast(attr_val.c_str())); } -bool StepMergeXml::SetTpkPrivilegeType() { - xmlXPathContextPtr xpath_ctx = xmlXPathNewContext(tpk_doc_); +bool StepMergeXml::SetTpkPrivilegeType(xmlDocPtr tpk_doc) { + xmlXPathContextPtr xpath_ctx = xmlXPathNewContext(tpk_doc); if (!xpath_ctx) { LOG(ERROR) << "Failed to create XPath context"; return false; @@ -152,19 +145,30 @@ ci::Step::Status StepMergeXml::process() { bf::path wgt_xml_path = context_->xml_path.get(); bf::path tpk_xml_path = context_->GetPkgPath() / "tizen-manifest.xml"; - if (!LoadXmlDocument(wgt_xml_path, tpk_xml_path)) + xmlDocPtr wgt_doc = LoadXmlDocument(wgt_xml_path); + if (wgt_doc == nullptr) return Step::Status::MANIFEST_ERROR; - if (!SetTpkPrivilegeType()) + auto wgt_doc_ptr = std::unique_ptr::type, + decltype(xmlFreeDoc)*>(wgt_doc, xmlFreeDoc); + + xmlDocPtr tpk_doc = LoadXmlDocument(tpk_xml_path); + if (tpk_doc == nullptr) + return Step::Status::MANIFEST_ERROR; + + auto tpk_doc_ptr = std::unique_ptr::type, + decltype(xmlFreeDoc)*>(tpk_doc, xmlFreeDoc); + + if (!SetTpkPrivilegeType(tpk_doc)) return Step::Status::MANIFEST_ERROR; for (auto& entry : kNeedMergeNodes) { - xmlNodePtr tpk_node = GetXmlNode(tpk_doc_, entry); + xmlNodePtr tpk_node = GetXmlNode(tpk_doc, entry); if (tpk_node == nullptr) continue; // TODO(s89.jang): If cannot find node from wgt doc, merge tpk node itself // instead of merging its child nodes. - xmlNodePtr wgt_node = GetXmlNode(wgt_doc_, entry); + xmlNodePtr wgt_node = GetXmlNode(wgt_doc, entry); MergeXmlNode(wgt_node, tpk_node); } @@ -183,11 +187,11 @@ ci::Step::Status StepMergeXml::process() { LOG(WARNING) << "Cannot find component type!"; continue; } - xmlNodePtr node = GetXmlNode(wgt_doc_, (*r).first, "appid", app->appid); + xmlNodePtr node = GetXmlNode(wgt_doc, (*r).first, "appid", app->appid); SetXmlNodeAttribute(node, "exec", app->exec); } - if (xmlSaveFormatFile(wgt_xml_path.string().c_str(), wgt_doc_, 1) == -1) { + if (xmlSaveFormatFile(wgt_xml_path.string().c_str(), wgt_doc, 1) == -1) { LOG(ERROR) << "Cannot write xml file"; return Step::Status::MANIFEST_ERROR; } diff --git a/src/hybrid/step/pkgmgr/step_merge_xml.h b/src/hybrid/step/pkgmgr/step_merge_xml.h index a373bcf..e9e606b 100644 --- a/src/hybrid/step/pkgmgr/step_merge_xml.h +++ b/src/hybrid/step/pkgmgr/step_merge_xml.h @@ -20,24 +20,20 @@ class StepMergeXml : public common_installer::Step { public: using Step::Step; explicit StepMergeXml(common_installer::InstallerContext* context) - : Step(context), wgt_doc_(nullptr), tpk_doc_(nullptr) {} + : Step(context) {} Status process() override; Status clean() override { return Status::OK; } Status undo() override { return Status::OK; } Status precheck() override; private: - bool LoadXmlDocument(const boost::filesystem::path& wgt_xml_path, - const boost::filesystem::path& tpk_xml_path); + xmlDocPtr LoadXmlDocument(const boost::filesystem::path& xml_path); xmlNodePtr GetXmlNode(const xmlDocPtr doc, const std::string& name, const std::string& attr = {}, const std::string& attr_val = {}); void MergeXmlNode(xmlNodePtr node1, xmlNodePtr node2); void SetXmlNodeAttribute(xmlNodePtr node, const std::string& attr, const std::string& attr_val); - bool SetTpkPrivilegeType(); - - xmlDocPtr wgt_doc_; - xmlDocPtr tpk_doc_; + bool SetTpkPrivilegeType(xmlDocPtr tpk_doc); STEP_NAME(MergeXml); }; -- 2.7.4 From 790434f00ab0c54dfbaa34a4a6dd9195435c58a5 Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Fri, 25 Sep 2020 16:50:48 +0900 Subject: [PATCH 08/16] Fix memory leak After using glob(), the glob_t should be freed using globfree() After using xmlReadFile(), the return value shoud be freed using xmlFreeDoc() Change-Id: I84a514e0849eb85ccf23834770c39d3d3220f635 Signed-off-by: Ilho Kim --- src/wgt/step/security/step_check_extension_privileges.cc | 1 + src/wgt/utils/extension_config_parser.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/src/wgt/step/security/step_check_extension_privileges.cc b/src/wgt/step/security/step_check_extension_privileges.cc index affeb47..796022d 100755 --- a/src/wgt/step/security/step_check_extension_privileges.cc +++ b/src/wgt/step/security/step_check_extension_privileges.cc @@ -60,6 +60,7 @@ common_installer::Step::Status StepCheckExtensionPrivileges::process() { for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) { xmlFiles.insert(glob_result.gl_pathv[i]); } + globfree(&glob_result); } GList* privileges = nullptr; BOOST_SCOPE_EXIT_ALL(privileges) { diff --git a/src/wgt/utils/extension_config_parser.cc b/src/wgt/utils/extension_config_parser.cc index 7a448a4..684c292 100644 --- a/src/wgt/utils/extension_config_parser.cc +++ b/src/wgt/utils/extension_config_parser.cc @@ -42,6 +42,7 @@ std::unique_ptr std::unique_ptr result(new parser::DictionaryValue); if (dv) result->Set(reinterpret_cast(root_node->name), dv.release()); + xmlFreeDoc(doc); return result; } -- 2.7.4 From e2bafbea5eb0733ab514b1ae66ba1e2cb44f8328 Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Tue, 27 Oct 2020 14:26:30 +0900 Subject: [PATCH 09/16] Release version 0.15.11 Changes: - Add recovery test for ReadonlyUpdateInstall - Change WgtAppQueryInterface's logic of clearing tmp path - Fix memory leak - Fix memory leak Change-Id: I1cd3a5f86fd7446e47e90ca27097156dbf4612ae Signed-off-by: Ilho Kim --- packaging/wgt-backend.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/wgt-backend.spec b/packaging/wgt-backend.spec index 849109b..643dac2 100644 --- a/packaging/wgt-backend.spec +++ b/packaging/wgt-backend.spec @@ -1,6 +1,6 @@ Name: wgt-backend Summary: Application installer backend for WGT -Version: 0.15.10 +Version: 0.15.11 Release: 1 Group: Application Framework/Package Management License: Apache-2.0 -- 2.7.4 From aead408d2d07421f2c5dc12d2c0fb317695f3b7d Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Thu, 26 Nov 2020 11:51:55 +0900 Subject: [PATCH 10/16] Add wgt package version policy If given version string is not start with allowed pattern, GetPackageVersion() will return empty string. This patch will check its result and fails entire install procedure if so. Change-Id: I14ebc962f0dd7167b9d166a4844960744216fc9b Signed-off-by: Junghyun Yeon --- src/wgt/step/configuration/step_parse.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wgt/step/configuration/step_parse.cc b/src/wgt/step/configuration/step_parse.cc index 8c97c72..d4c677b 100644 --- a/src/wgt/step/configuration/step_parse.cc +++ b/src/wgt/step/configuration/step_parse.cc @@ -249,7 +249,12 @@ bool StepParse::FillWidgetInfo(manifest_x* manifest) { const std::string& version = wgt_info->version(); manifest->ns = strdup(kTizenPackageXmlNamespace); - manifest->version = strdup(GetPackageVersion(version).c_str()); + std::string version_tmp = GetPackageVersion(version); + if (version_tmp.empty()) { + LOG(ERROR) << "Invalid version format : " << version; + return false; + } + manifest->version = strdup(version_tmp.c_str()); for (auto& item : wgt_info->description_set()) { description_x* description = reinterpret_cast -- 2.7.4 From 4be17abaca68af2eb3f0f2fd3236925505d6db1e Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Tue, 1 Dec 2020 09:19:02 +0900 Subject: [PATCH 11/16] Release version 0.15.12 Changes: - Add wgt package version policy Change-Id: I791c6908ad855d1a74845cd7a7884b96c89d9797 Signed-off-by: Junghyun Yeon --- packaging/wgt-backend.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/wgt-backend.spec b/packaging/wgt-backend.spec index 643dac2..e2c839d 100644 --- a/packaging/wgt-backend.spec +++ b/packaging/wgt-backend.spec @@ -1,6 +1,6 @@ Name: wgt-backend Summary: Application installer backend for WGT -Version: 0.15.11 +Version: 0.15.12 Release: 1 Group: Application Framework/Package Management License: Apache-2.0 -- 2.7.4 From 6f384a8587ca00337baf0889901c79cdf6d7d91c Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Mon, 4 Jan 2021 16:37:39 +0900 Subject: [PATCH 12/16] Fix wgt version checking logic WGT version string could contain non UTF-8 characters. Now version checking logic will skip validation if given character is non UTF-8. Change-Id: I869fab0b8f12ece90735e71a71ec62b0e84c806c Signed-off-by: Junghyun Yeon --- src/wgt/step/configuration/step_parse.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/wgt/step/configuration/step_parse.cc b/src/wgt/step/configuration/step_parse.cc index d4c677b..3b46e7e 100644 --- a/src/wgt/step/configuration/step_parse.cc +++ b/src/wgt/step/configuration/step_parse.cc @@ -171,14 +171,22 @@ std::set StepParse::ExtractPrivileges( } std::string StepParse::GetPackageVersion( - const std::string& manifest_version) { - if (manifest_version.empty()) { + const std::string& manifest_version) { + if (manifest_version.empty()) return kManifestVersion; - } - std::string version = manifest_version.substr(0, - manifest_version.find_first_not_of("1234567890.")); - return version; + for (const char& c : manifest_version) { + // first bit of 1 byte utf-8 character is always 0 + if (c >> 7 == 1) + continue; + + if (std::string(1, c).find_first_not_of("1234567890.") != + std::string::npos) { + LOG(ERROR) << "Invalid version format"; + return nullptr; + } + } + return manifest_version; } bool StepParse::FillInstallationInfo(manifest_x* manifest) { -- 2.7.4 From b9c9fb56d5199ac3e53eb15a4692b87b391187fa Mon Sep 17 00:00:00 2001 From: Ilho Kim Date: Thu, 7 Jan 2021 14:14:48 +0900 Subject: [PATCH 13/16] Release version 0.15.13 Changes: - Fix wgt version checking logic Change-Id: I50da224ce2e0666cf9ee145c06906c7a8d845cf5 Signed-off-by: Ilho Kim --- packaging/wgt-backend.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/wgt-backend.spec b/packaging/wgt-backend.spec index e2c839d..416f4f3 100644 --- a/packaging/wgt-backend.spec +++ b/packaging/wgt-backend.spec @@ -1,6 +1,6 @@ Name: wgt-backend Summary: Application installer backend for WGT -Version: 0.15.12 +Version: 0.15.13 Release: 1 Group: Application Framework/Package Management License: Apache-2.0 -- 2.7.4 From 9042be6419320211c4c4d73067ed0db8a84083a0 Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Tue, 12 Jan 2021 13:57:19 +0900 Subject: [PATCH 14/16] Fix memory leak Related changes: [app-installers] : https://review.tizen.org/gerrit/251120 Change-Id: I965336477aeec7dd2dae2dd274514c1fbc9c5199 Signed-off-by: Junghyun Yeon --- src/hybrid/hybrid_installer_factory.cc | 3 ++- src/wgt/wgt_installer_factory.cc | 2 +- src/wgt_backend/wgt_backend.cc | 7 ++++--- test/smoke_tests/smoke_test_helper.cc | 5 +++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/hybrid/hybrid_installer_factory.cc b/src/hybrid/hybrid_installer_factory.cc index ed9cf2a..1716765 100644 --- a/src/hybrid/hybrid_installer_factory.cc +++ b/src/hybrid/hybrid_installer_factory.cc @@ -25,7 +25,8 @@ namespace hybrid { std::unique_ptr HybridInstallerFactory::CreateInstaller( ci::PkgMgrPtr pkgmgr, int idx) { std::unique_ptr installer; - wgt::WgtAppQueryInterface* wgt_aqi = new wgt::WgtAppQueryInterface(); + std::shared_ptr wgt_aqi( + new wgt::WgtAppQueryInterface()); pkgmgr->AddAppQueryInterface(idx, wgt_aqi); installer.reset(new hybrid::HybridInstaller(pkgmgr)); diff --git a/src/wgt/wgt_installer_factory.cc b/src/wgt/wgt_installer_factory.cc index 54d191e..f260647 100644 --- a/src/wgt/wgt_installer_factory.cc +++ b/src/wgt/wgt_installer_factory.cc @@ -25,7 +25,7 @@ namespace wgt { std::unique_ptr WgtInstallerFactory::CreateInstaller( ci::PkgMgrPtr pkgmgr, int idx) { std::unique_ptr installer; - WgtAppQueryInterface* wgt_aqi = new WgtAppQueryInterface(); + std::shared_ptr wgt_aqi(new WgtAppQueryInterface()); pkgmgr->AddAppQueryInterface(idx, wgt_aqi); installer.reset(new wgt::WgtInstaller(pkgmgr)); diff --git a/src/wgt_backend/wgt_backend.cc b/src/wgt_backend/wgt_backend.cc index 3286b08..54c070f 100644 --- a/src/wgt_backend/wgt_backend.cc +++ b/src/wgt_backend/wgt_backend.cc @@ -28,10 +28,11 @@ std::unique_ptr make_unique(Args&&... args) { int main(int argc, char** argv) { ci::PkgmgrInstaller pkgmgr_installer; - wgt::WgtAppQueryInterface query_interface; + std::shared_ptr query_interface( + new wgt::WgtAppQueryInterface()); try { auto pkgmgr = ci::PkgMgrInterface::Create(argc, argv, &pkgmgr_installer, - &query_interface); + query_interface); std::unique_ptr installer_factory; if (!pkgmgr) { LOG(ERROR) << "Options of pkgmgr installer cannot be parsed"; @@ -43,7 +44,7 @@ int main(int argc, char** argv) { #endif // This is workaround for hybrid apps as they requires much different flow // but installer does not branch at all in current design - if (query_interface.IsHybridApplication( + if (query_interface->IsHybridApplication( pkgmgr->GetRequestInfo(), pkgmgr->GetUid())) { LOG(INFO) << "Hybrid package detected"; ci::InstallerRunner runner( diff --git a/test/smoke_tests/smoke_test_helper.cc b/test/smoke_tests/smoke_test_helper.cc index a52afa2..45dbacc 100644 --- a/test/smoke_tests/smoke_test_helper.cc +++ b/test/smoke_tests/smoke_test_helper.cc @@ -38,9 +38,10 @@ int main(int argc, char** argv) { } ci::PkgmgrInstaller pkgmgr_installer; - wgt::WgtAppQueryInterface query_interface; + std::shared_ptr query_interface( + new wgt::WgtAppQueryInterface()); auto pkgmgr = ci::PkgMgrInterface::Create(backend_argc, argv, - &pkgmgr_installer, &query_interface); + &pkgmgr_installer, query_interface); if (!pkgmgr) { LOG(ERROR) << "Options of pkgmgr installer cannot be parsed"; return EINVAL; -- 2.7.4 From 2365dc0731f1e1ea799b6f10023066f795ea0f29 Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Fri, 15 Jan 2021 10:06:09 +0900 Subject: [PATCH 15/16] Release version 0.15.14 Changes: - Fix memory leak Change-Id: Ifc43e4fb049dffd6b4cbed1bb46e4b4ce779d346 Signed-off-by: Junghyun Yeon --- packaging/wgt-backend.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/wgt-backend.spec b/packaging/wgt-backend.spec index 416f4f3..9b6ff12 100644 --- a/packaging/wgt-backend.spec +++ b/packaging/wgt-backend.spec @@ -1,6 +1,6 @@ Name: wgt-backend Summary: Application installer backend for WGT -Version: 0.15.13 +Version: 0.15.14 Release: 1 Group: Application Framework/Package Management License: Apache-2.0 -- 2.7.4 From d17845057ff85ec9264e6ec892d60a136ac9e9c5 Mon Sep 17 00:00:00 2001 From: Junghyun Yeon Date: Fri, 15 Jan 2021 12:46:55 +0900 Subject: [PATCH 16/16] Fix step name Related changes: [app-installers] : https://review.tizen.org/gerrit/#/c/platform/core/appfw/app-installers/+/251363/ Change-Id: Ia5add48927e9b50e2124f1a37b262f4298156aaf Signed-off-by: Junghyun Yeon --- src/wgt/wgt_installer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wgt/wgt_installer.cc b/src/wgt/wgt_installer.cc index 12f151c..5b023ae 100644 --- a/src/wgt/wgt_installer.cc +++ b/src/wgt/wgt_installer.cc @@ -73,7 +73,7 @@ void WgtInstaller::InstallSteps() { AddStepAfter("EncryptResources"); RemoveStep("CreateIcons"); AddStepAfter( - "CopyTEP"); + "CopyTep"); AddStepAfter( "WgtPatchStorageDirectories"); AddStepAfter( -- 2.7.4