[Linux] 使用 diff 指令產生補丁檔,用 patch 指令幫程式上補丁

[Linux] 使用 diff 指令產生補丁檔,用 patch 指令幫程式上補丁

patch 這個指令在 Linux 裡面很常看到,不過自己沒有實際用過…

今天正好有個機會,要幫 p7zip 上一個 security patch,

就來試試看吧~

 

參考資料:

7 Patch Command Examples to Apply Diff Patch Files in Linux

Diff 和 Patch 的簡易操作使用筆記

Apply multiple .patch files

 

1. 取得 patch 檔案

因為這次的課題是修補 p7zip,patch 檔網路上已經有了,

因此直接抓下來就好了~內容節錄如下:

--- a/CPP/7zip/UI/Agent/Agent.cpp
+++ b/CPP/7zip/UI/Agent/Agent.cpp
@@ -424,6 +424,8 @@ STDMETHODIMP CAgentFolder::Extract(const
CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
UStringVector pathParts;
CProxyFolder *currentProxyFolder = _proxyFolderItem;
+  HRESULT res;
+
while (currentProxyFolder->Parent)
{
pathParts.Insert(0, currentProxyFolder->Name);
@@ -445,8 +447,11 @@ STDMETHODIMP CAgentFolder::Extract(const
(UInt64)(Int64)-1);
CUIntVector realIndices;
GetRealIndices(indices, numItems, realIndices);
-  return _agentSpec->GetArchive()->Extract(&realIndices.Front(),
+  res = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
realIndices.Size(), testMode, extractCallback);
+  if (res == S_OK && !extractCallbackSpec->CreateSymLinks())
+    res = E_FAIL;
+  return res;
COM_TRY_END
}

 

如果是要自己產生 patch 檔案的話,可以用 diff 指令~

通常是將舊的檔案放在一個目錄 old,

整個複製成另一個目錄 new 後,再去修改 new 目錄裡的檔案,

等修改都完成後,就可以下 diff 指令:

testuser@localhost ~ $ diff -Naur old new
diff -Naur old/CPP/7zip/Crypto/Sha1.cpp new/CPP/7zip/Crypto/Sha1.cpp
--- old/CPP/7zip/Crypto/Sha1.cpp	2010-10-20 12:56:08.000000000 +0800
+++ new/CPP/7zip/Crypto/Sha1.cpp	2016-03-18 15:49:30.000000000 +0800
@@ -145,13 +145,13 @@
curBufferPos = 0;
CContextBase::UpdateBlock(_buffer, returnRes);
if (returnRes)
-        for (int i = 0; i < kBlockSizeInWords; i++)
+        for (unsigned i = 0; i < kBlockSizeInWords; i++)
{
UInt32 d = _buffer[i];
-          data[i * 4 + 0 - kBlockSize] = (Byte)(d);
-          data[i * 4 + 1 - kBlockSize] = (Byte)(d >>  8);
-          data[i * 4 + 2 - kBlockSize] = (Byte)(d >> 16);
-          data[i * 4 + 3 - kBlockSize] = (Byte)(d >> 24);
+          data[(int)i * 4 + 0 - (int)kBlockSize] = (Byte)(d);
+          data[(int)i * 4 + 1 - (int)kBlockSize] = (Byte)(d >>  8);
+          data[(int)i * 4 + 2 - (int)kBlockSize] = (Byte)(d >> 16);
+          data[(int)i * 4 + 3 - (int)kBlockSize] = (Byte)(d >> 24);
}
returnRes = rar350Mode;
}

 

用來產生補丁檔的 diff 指令,通常會帶 -Naur 這幾個選項,分別代表:

-a 將所有檔案都視為文字檔
-u 輸出預設三行的相同文字行
-r 遞迴比較所有的子目錄
-N 將缺少的檔案視為空檔案

 

將 diff 的結果用 > 轉向寫到一個 xxx.patch 檔,之後就可以用 patch 指令來下補丁了~

 

2. 使用 patch 來上補丁

先把要修補的原始碼準備好,在本例中是要去下載 p7zip 7.20.1 的原始碼下來解開,

再執行 patch -i patch_file 或是 patch < patch_file:

testuser@localhost ~/p7zip_9.20.1 $ patch -i ../CVE-2015-1038.patch
can't find file to patch at input line 1
Perhaps you should have used the -p or --strip option?
The text leading up to this was:
--------------------------
|--- a/CPP/7zip/UI/Agent/Agent.cpp
|+++ b/CPP/7zip/UI/Agent/Agent.cpp
--------------------------
File to patch:

 

在上例中,因為 patch 檔是用兩個目錄比較的方式產生的,

可以看到原始碼分別放在 a 和 b 兩個目錄下做比較,

但我們的原始碼並沒有 a 和 b 目錄,所以 patch 就搞不懂狀況了…

這時要多加一個 -p1 的參數,代表要跳過一層目錄結構,

如果 patch 檔產生時是在更深層的目錄結構的話,可能就會用到 -p2, -p3, …

 

加上 -p1 後,patch 就成功了:

testuser@localhost ~/p7zip_9.20.1 $ patch -p1 -i ../CVE-2015-1038.patch
patching file CPP/7zip/UI/Agent/Agent.cpp
patching file CPP/7zip/UI/Agent/ArchiveFolder.cpp
patching file CPP/7zip/UI/Client7z/Client7z.cpp
patching file CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
patching file CPP/7zip/UI/Common/ArchiveExtractCallback.h
patching file CPP/7zip/UI/Common/Extract.cpp
patching file CPP/Windows/FileDir.cpp
patching file CPP/Windows/FileDir.h

 

如果在 patch 前不放心的話,可以加上 –dry-run 參數試跑,

不會真的去上補丁,而只是給你看會修改哪些檔案,以及是否會成功~

 

在上面的例子裡面,我的輸入都是用 patch -i patch_file 的方式,

不過網路上似乎更多人偏愛 patch < patch_file 的方式,

但是要注意的是如果有多個 patch 檔的話,用 < 轉向的方式是不行的喔~

這時可以用 cat 再 pipe 給 patch 的方式,例如:

cat *.patch | patch -p1

 

(本頁面已被瀏覽過 34,646 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料