I have had a lot of questions lately about making patches. On Backtrack we get a lot of user submissions and many times we need a patch rather than a modified source file. The reason being is that a patch can be documented and contains the specific changes made to the source file and can also be easily reverted. Patching is also crucial if you fix a bug in a program and would like to submit the fix to the author. In any case being able to create a patch is very useful if you are working with Linux or any sort of programing stuff.
I decided to make a short post on how to make a patch and apply it:
So here is the scenario. You download a piece of code and it doesn’t work on your computer. You spend all day tweaking the script and making it work so that when it finally does work you totally forgot what you did. While you may have made good comments, thats not always good enough. So this is where diff and patch come in. In my example I am using a .py file that a friend of mine submitted to me to fix a issue in a python script by Edge Security called The Harvester. Since the program is still active it would be uncool just to replace the original script in our .deb package so instead I made a patch.
So here is the scenario:
- root@bt:~# ls -laprt | grep .py
- -rwx------ 1 root root 6553 Jul 13 12:19 Edited_theHarvester.py
- -rwx------ 1 root root 5722 Jul 13 14:45 Orig_theHarvester.py
So I have to files one of which is the original and one is the one which was submitted to me modified and is working they way we want.
Just to illustrate the point here is a diff of the two files:
- root@bt:~# diff Orig_theHarvester.py Edited_theHarvester.py
- 91c91
- <
- ---
- > #print data
- 95a96
- > host = [] #this is needed. We need to return 3 items, else python quits out.
- 97,98c98,100
- < y = string.replace(x, ' | LinkedIn</a>', '')
- < y = string.replace(x, '- Directory', '')
- ---
- > y = string.replace(x, 'LinkedIn', '') #was replacing ' | LinkedIn</a> but it was not weeding out the entries that were simply 'LinkedIn</a'
- > y = string.replace(y, '</a', '') #added
- > y = string.replace(y, '- Directory', '') #this was 'y = string.replace(x, '- Directory', '') which I think was a typo, as y would now be equal to original x without the changes made concerning 'LinkedIn' and '</a' entries.
- 101,102c103,109
- < resul.append(y)
- < return resul,nexty
- ---
- > y.strip(' \n\t\r')
- > if len(y) == 1: #this block weeds out strings of length 1 that are only a whitespace
- > if ord(y) == 32:
- > continue
- > if len(y) != 0: #checks for zero length strings, which probably wont happen
- > resul.append(y)
- > return resul,nexty,host #as stated above, only returning resul,nexty makes python quit.
- 161c168
- < res,nexty,host = run(word, cant, engine)
- ---
- > res,nexty,host = run(word, cant, engine) #I placed a print after this line and found python never got that far. After having run return 3 items for linkedin, it now finishes
- 163,164c170,172
- < if result.count(x) == 0:
- < result.append(x)
- ---
- > if result.count(x) == 0:
- > result.append(x)
- > print len(result)
- 166,167c174,175
- < if resulthost.count(x) == 0:
- < resulthost.append(x)
- ---
- > if resulthost.count(x) == 0:
- > resulthost.append(x)
- root@bt:~#
Okay so there are obviously a few differences so lets make a patch:
- root@bt:~# diff -u Orig_theHarvester.py Edited_theHarvester.py > harvester.patch
Thats it! No we have a patch which we can submit to the maintainers of which ever project we just fixed.
Now lets apply the patch and check our work:
- root@bt:~# patch Orig_theHarvester.py < harvester.patch
- patching file Orig_theHarvester.py
And then lets do another diff to see if it worked:
- root@bt:~# diff Orig_theHarvester.py Edited_theHarvester.py
- root@bt:~#
w00t! No output means our two files are exactly the same and the patch has worked properly
So that works but now you are maybe asking “what if I modified a bunch of files in a directory in order to get the program to work?”. It works pretty much the same way with a few extras.
First thing to do is make a copy of the entire directory:
- root@bt:~# cp -R tool_X/ Edited_tool_X
- root@bt:~#
Once you do that then you make all your changes to the new edited directory and then apply the diff command like this:
- root@bt:~# diff -rupN tool_X/ Edited_tool_X > toolX.patch
- root@bt:~#
Applying patches to entire directories is similar, but you have to set a p level. The p level instructs patch to ignore parts of the path name so that it can identify the files correctly.
Normally a p setting of 1 is sufficient. Change into the top level directory and apply the patch:
- root@bt:~# mv toolX.patch tool_X/
- root@bt:~# cd tool_X/
- root@bt:~/tool_X# patch -p1 < toolX.patch
- root@bt:~/tool_X#
Count up one for each path separator (slash character) that you remove from the beginning of the path, until what’s left is a path that exists in your working directory. The count you reach is the p level.
If at anytime you need to remove a patch you can do so with the -R option:
- root@bt:~# patch -R Orig_theHarvester.py < harvester.patch
- patching file Orig_theHarvester.py
Thats it for a basic intro to patching files and directories!