Skip to content

Commit b092126

Browse files
committed
Fixes #27 - Add option to swap endian
Uses -E in the in cli and checkbox in GUI
1 parent 7be2ec3 commit b092126

File tree

5 files changed

+52
-18
lines changed

5 files changed

+52
-18
lines changed

readme.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ If needed you can use the folowing options to customize the behaviour of *tapeim
105105
|**Prefix**|Output prefix (default: `file`).|
106106
|**Extension**|Output file extension (default: `dd`).|
107107
|**Fill failed blocks**|Fill blocks that give read errors with null bytes. When this option is checked, *tapeimgr* calls *dd* with the flags `conv=noerror,sync`. The use of these flags is often recommended to ensure a forensic image with no missing/offset bytes in case of read errors (source: [*forensicswiki*](https://www.forensicswiki.org/wiki/Dd)), but when used with a block size that is larger than the actual block size it will generate padding bytes that make the extracted data unreadable. Because of this, any user-specified value of the **Initial Block Size** setting (see above) is ignored when this option is used. **WARNING: this option may result in malformed output if the actual block size is either smaller than 512 bytes, and/or if the block size is not a multiple of 512 bytes! (I have no idea if this is even possible?).**|
108+
|**Swap little/big endian**|Use this option to swap the endianness of the file by adding `conv=swab` *dd* option. This is needed most commonly if the tape was created on an older [big endian OS](https://geraldonit.com/2017/09/04/big-and-little-endian-operating-systems/).|
108109
|**Identifier**|Unique identifier. You can either enter an existing identifier yourself, or press the *UUID* button to generate a [Universally unique identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier).|
109110
|**Description**|A text string that describes the tape (e.g. the title that is written on its inlay card).|
110111
|**Notes**|Any additional info or notes you want to record with the tape.|
@@ -113,11 +114,12 @@ If needed you can use the folowing options to customize the behaviour of *tapeim
113114

114115
It is also possible to invoke *tapeimgr* with command-line arguments. The general syntax is:
115116

116-
tapeimgr [-h] [--version] [--fill] [--device DEVICE]
117-
[--blocksize SIZE] [--files FILES] [--prefix PREF]
118-
[--extension EXT] [--identifier IDENTIFIER]
119-
[--description DESCRIPTION] [--notes NOTES]
120-
dirOut
117+
tapeimgr [-h] [--version] [--fill] [--endianswap]
118+
[--device DEVICE] [--blocksize SIZE] [--files FILES]
119+
[--prefix PREF] [--extension EXT]
120+
[--identifier IDENTIFIER]
121+
[--description DESCRIPTION] [--notes NOTES]
122+
dirOut
121123

122124
Here `dirOut` is the output directory. So, the command-line equivalent of the first GUI example is:
123125

@@ -141,6 +143,7 @@ As with the GUI interface you can customize the default behaviour by using one o
141143
|`--prefix PREF, -p PREF`|Output prefix (default: `file`).|
142144
|`--extension EXT, -e EXT`|Output file extension (default: `dd`).|
143145
|`--fill, -f`|Fill blocks that give read errors with null bytes. When this option is checked, *tapeimgr* calls *dd* with the flags `conv=noerror,sync`. The use of these flags is often recommended to ensure a forensic image with no missing/offset bytes in case of read errors (source: [*forensicswiki*](https://www.forensicswiki.org/wiki/Dd)), but when used with a block size that is larger than the actual block size it will generate padding bytes that make the extracted data unreadable. Because of this, any user-specified value of the `--blocksize`setting (see above) is ignored when this option is used. **WARNING: this option may result in malformed output if the actual block size is either smaller than 512 bytes, and/or if the block size is not a multiple of 512 bytes! (I have no idea if this is even possible?).**|
146+
|`--endianswap, -E`|Use this option to swap the endianness of the file by adding `conv=swab` *dd* option. This is needed most commonly if the tape was created on an older [big endian OS](https://geraldonit.com/2017/09/04/big-and-little-endian-operating-systems/).|
144147
|`--identifier IDENTIFIER, -i IDENTIFIER`|Unique identifier. You can either enter an existing identifier yourself, or enter special value `@uuid` to generate a [Universally unique identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier).|
145148
|`--description DESCRIPTION, -c DESCRIPTION `|A text string that describes the tape (e.g. the title that is written on its inlay card).|
146149
|`--notes NOTES, -n NOTES`|Any additional info or notes you want to record with the tape.|

tapeimgr/cli.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ def parseCommandLine(self):
5858
dest='fillBlocks',
5959
default=self.tape.fillBlocks,
6060
help='fill blocks that give read errors with null bytes')
61+
self.parser.add_argument('--endianswap', '-E',
62+
action='store_true',
63+
dest='endianSwap',
64+
default=self.tape.endianSwap,
65+
help='swap big/little endian')
6166
self.parser.add_argument('--device', '-d',
6267
action='store',
6368
type=str,
@@ -110,6 +115,7 @@ def parseCommandLine(self):
110115
args = self.parser.parse_args()
111116
self.tape.dirOut = args.dirOut
112117
self.tape.fillBlocks = args.fillBlocks
118+
self.tape.endianSwap = args.endianSwap
113119
self.tape.tapeDevice = args.device
114120
self.tape.initBlockSize = args.size
115121
self.tape.files = args.files

tapeimgr/configure.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def writeConfigFile(configRootDir, removeFlag):
5858
configSettings['prefix'] = 'file'
5959
configSettings['extension'] = 'dd'
6060
configSettings['fillBlocks'] = 'False'
61+
configSettings['endianSwap'] = 'False'
6162
configSettings['timeZone'] = 'Europe/Amsterdam'
6263
configSettings['defaultDir'] = ''
6364

tapeimgr/gui.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def on_submit(self, event=None):
7474
self.tape.description = self.description_entry.get().strip()
7575
self.tape.notes = self.notes_entry.get(1.0, tk.END).strip()
7676
self.tape.fillBlocks = self.fBlocks.get()
77+
self.tape.endianSwap = self.eSwap.get()
7778

7879
# Check if required command line utils are available
7980
for cmd in shared.REQUIRED_CMDS:
@@ -143,6 +144,7 @@ def on_submit(self, event=None):
143144
self.prefix_entry.config(state='disabled')
144145
self.extension_entry.config(state='disabled')
145146
self.fillblocks_entry.config(state='disabled')
147+
self.endianswap_entry.config(state='disabled')
146148
self.identifier_entry.config(state='disabled')
147149
self.uuidButton.config(state='disabled')
148150
self.description_entry.config(state='disabled')
@@ -262,7 +264,14 @@ def build_gui(self):
262264
self.fillblocks_entry = tk.Checkbutton(self, variable=self.fBlocks)
263265
self.fillblocks_entry.grid(column=1, row=11, sticky='w')
264266

265-
ttk.Separator(self, orient='horizontal').grid(column=0, row=12, columnspan=4, sticky='ew')
267+
# Swap Endian
268+
tk.Label(self, text='Swap little/big endian').grid(column=0, row=12, sticky='w')
269+
self.eSwap = tk.BooleanVar()
270+
self.eSwap.set(self.tape.endianSwap)
271+
self.endianswap_entry = tk.Checkbutton(self, variable=self.eSwap)
272+
self.endianswap_entry.grid(column=1, row=12, sticky='w')
273+
274+
ttk.Separator(self, orient='horizontal').grid(column=0, row=12+1, columnspan=4, sticky='ew')
266275

267276
# Identifier entry field
268277
tk.Label(self, text='Identifier').grid(column=0, row=13, sticky='w')
@@ -272,45 +281,45 @@ def build_gui(self):
272281
self.identifier_entry.grid(column=1, row=13, sticky='w')
273282
self.uuidButton = tk.Button(self, text='UUID', underline=0,
274283
command=self.insertUUID, width=2)
275-
self.uuidButton.grid(column=1, row=13, sticky='e')
284+
self.uuidButton.grid(column=1, row=13+1, sticky='e')
276285

277286
# Description entry field
278287
tk.Label(self, text='Description').grid(column=0, row=14, sticky='w')
279288
self.description_entry = tk.Entry(self, width=35)
280289
self.description_entry['background'] = 'white'
281290
self.description_entry.insert(tk.END, self.tape.description)
282-
self.description_entry.grid(column=1, row=14, sticky='w', columnspan=1)
291+
self.description_entry.grid(column=1, row=14+1, sticky='w', columnspan=1)
283292

284293
# Notes entry field
285294
tk.Label(self, text='Notes').grid(column=0, row=15, sticky='w')
286295
self.notes_entry = tk.Text(self, height=6, width=35)
287296
self.notes_entry['background'] = 'white'
288297
self.notes_entry.insert(tk.END, self.tape.notes)
289-
self.notes_entry.grid(column=1, row=15, sticky='w', columnspan=1)
298+
self.notes_entry.grid(column=1, row=15+1, sticky='w', columnspan=1)
290299

291-
ttk.Separator(self, orient='horizontal').grid(column=0, row=16, columnspan=4, sticky='ew')
300+
ttk.Separator(self, orient='horizontal').grid(column=0, row=16+1, columnspan=4, sticky='ew')
292301

293302
self.start_button = tk.Button(self,
294303
text='Start',
295304
width=10,
296305
underline=0,
297306
command=self.on_submit)
298-
self.start_button.grid(column=1, row=17, sticky='w')
307+
self.start_button.grid(column=1, row=17+1, sticky='w')
299308

300309
self.quit_button = tk.Button(self,
301310
text='Exit',
302311
width=10,
303312
underline=0,
304313
command=self.on_quit)
305-
self.quit_button.grid(column=1, row=17, sticky='e')
314+
self.quit_button.grid(column=1, row=17+1, sticky='e')
306315

307-
ttk.Separator(self, orient='horizontal').grid(column=0, row=18, columnspan=4, sticky='ew')
316+
ttk.Separator(self, orient='horizontal').grid(column=0, row=18+1, columnspan=4, sticky='ew')
308317

309318
# Add ScrolledText widget to display logging info
310319
self.st = ScrolledText.ScrolledText(self, state='disabled', height=15)
311320
self.st.configure(font='TkFixedFont')
312321
self.st['background'] = 'white'
313-
self.st.grid(column=0, row=19, sticky='ew', columnspan=4)
322+
self.st.grid(column=0, row=19+1, sticky='ew', columnspan=4)
314323

315324
# Define bindings for keyboard shortcuts: buttons
316325
self.root.bind_all('<Control-Key-d>', self.selectOutputDirectory)
@@ -350,6 +359,7 @@ def reset_gui(self, dirOut):
350359
self.prefix_entry.config(state='normal')
351360
self.extension_entry.config(state='normal')
352361
self.fillblocks_entry.config(state='normal')
362+
self.endianswap_entry.config(state='normal')
353363
self.identifier_entry.config(state='normal')
354364
self.uuidButton.config(state='normal')
355365
self.description_entry.config(state='normal')
@@ -375,6 +385,7 @@ def reset_gui(self, dirOut):
375385
self.notes_entry.delete(1.0, tk.END)
376386
self.notes_entry.insert(tk.END, self.tape.notes)
377387
self.fBlocks.set(self.tape.fillBlocks)
388+
self.eSwap.set(self.tape.endianSwap)
378389
self.start_button.config(state='normal')
379390
self.quit_button.config(state='normal')
380391

tapeimgr/tape.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def __init__(self):
2525
self.prefix = ''
2626
self.extension = ''
2727
self.fillBlocks = ''
28+
self.endianSwap = ''
2829
self.identifier = ''
2930
self.description = ''
3031
self.notes = ''
@@ -86,8 +87,10 @@ def getConfiguration(self):
8687
self.prefix = configDict['prefix']
8788
self.extension = configDict['extension']
8889
self.fillBlocks = configDict['fillBlocks']
89-
# Convert fillBlocks to Boolean
90+
self.endianSwap = configDict['endianSwap']
91+
# Convert fillBlocks/endianSwap to Boolean
9092
self.fillBlocks = bool(self.fillBlocks == "True")
93+
self.endianSwap = bool(self.endianSwap == "True")
9194
self.timeZone = configDict['timeZone']
9295
self.defaultDir = configDict['defaultDir']
9396
except KeyError:
@@ -167,6 +170,7 @@ def processTape(self):
167170
logging.info('prefix: ' + self.prefix)
168171
logging.info('extension: ' + self.extension)
169172
logging.info('fill blocks: ' + str(self.fillBlocks))
173+
logging.info('endian swap: ' + str(self.endianSwap))
170174

171175
## Acquisition start date/time
172176
acquisitionStart = shared.generateDateTime(self.timeZone)
@@ -251,6 +255,7 @@ def processTape(self):
251255
metadata['prefix'] = self.prefix
252256
metadata['extension'] = self.extension
253257
metadata['fillBlocks'] = self.fillBlocks
258+
metadata['endianSwap'] = self.endianSwap
254259
metadata['acquisitionStart'] = acquisitionStart
255260
metadata['acquisitionEnd'] = acquisitionEnd
256261
metadata['successFlag'] = self.successFlag
@@ -302,9 +307,17 @@ def processFile(self):
302307
args.append('of='+ ofName)
303308
args.append('bs=' + str(self.blockSize))
304309

305-
if self.fillBlocks:
306-
# Add conv=noerror,sync options to argument list
307-
args.append('conv=noerror,sync')
310+
if self.fillBlocks or self.endianSwap:
311+
conversionOpts = []
312+
if self.fillBlocks:
313+
# Add conv=noerror,sync options to argument list
314+
conversionOpts.append('noerror')
315+
conversionOpts.append('sync')
316+
if self.endianSwap:
317+
# Add conv=swab for endian conversion
318+
conversionOpts.append('swab')
319+
320+
args.append('conv=' + ','.join(conversionOpts))
308321

309322
ddStatus, ddOut, ddErr = shared.launchSubProcess(args)
310323

0 commit comments

Comments
 (0)