Skip to content

Commit bbe9109

Browse files
authored
Merge pull request darktable-org#469 from wpferguson/win_sanitize
Sanitize windows command interactions
2 parents 34d5df6 + 9f2dbef commit bbe9109

16 files changed

+99
-33
lines changed

contrib/autostyle.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ GPLv2
3939
local darktable = require "darktable"
4040
local du = require "lib/dtutils"
4141
local filelib = require "lib/dtutils.file"
42+
local syslib = require "lib/dtutils.system"
4243

4344
du.check_min_api_version("7.0.0", "autostyle")
4445

@@ -68,7 +69,7 @@ script_data.show = nil -- only required for libs since the destroy_method only h
6869
-- run command and retrieve stdout
6970
local function get_stdout(cmd)
7071
-- Open the command, for reading
71-
local fd = assert(io.popen(cmd, 'r'))
72+
local fd = assert(syslib.io_popen(cmd, 'r'))
7273
darktable.control.read(fd)
7374
-- slurp the whole file
7475
local data = assert(fd:read('*a'))

contrib/color_profile_manager.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
local dt = require "darktable"
4646
local du = require "lib/dtutils"
4747
local df = require "lib/dtutils.file"
48+
local dtsys = require "lib/dtutils.system"
4849

4950
du.check_min_api_version("7.0.0", "color_profile_manager")
5051

@@ -106,7 +107,7 @@ end
106107

107108
local function list_profiles(dir)
108109
local files = {}
109-
local p = io.popen(DIR_CMD .. " " .. dir)
110+
local p = dtsys.io_popen(DIR_CMD .. " " .. dir)
110111
if p then
111112
for line in p:lines() do
112113
table.insert(files, line)

contrib/fujifilm_dynamic_range.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ cameras may behave in other ways.
6060
local dt = require "darktable"
6161
local du = require "lib/dtutils"
6262
local df = require "lib/dtutils.file"
63+
local dtsys = require "lib/dtutils.system"
6364
local gettext = dt.gettext.gettext
6465

6566
du.check_min_api_version("7.0.0", "fujifilm_dynamic_range")
@@ -105,7 +106,7 @@ local function detect_dynamic_range(event, image)
105106
-- without -n flag, exiftool will round to the nearest tenth
106107
command = command .. " -RawExposureBias -n -t " .. RAF_filename
107108
dt.print_log(command)
108-
output = io.popen(command)
109+
output = dtsys.io_popen(command)
109110
local raf_result = output:read("*all")
110111
output:close()
111112
if #raf_result == 0 then

contrib/fujifilm_ratings.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Dependencies:
2626
local dt = require "darktable"
2727
local du = require "lib/dtutils"
2828
local df = require "lib/dtutils.file"
29+
local dtsys = require "lib/dtutils.system"
2930
local gettext = dt.gettext.gettext
3031

3132
du.check_min_api_version("7.0.0", "fujifilm_ratings")
@@ -61,7 +62,7 @@ local function detect_rating(event, image)
6162
local JPEG_filename = string.gsub(RAF_filename, "%.RAF$", ".JPG")
6263
local command = "exiftool -Rating " .. JPEG_filename
6364
dt.print_error(command)
64-
local output = io.popen(command)
65+
local output = dtsys.io_popen(command)
6566
local jpeg_result = output:read("*all")
6667
output:close()
6768
if string.len(jpeg_result) > 0 then
@@ -72,7 +73,7 @@ local function detect_rating(event, image)
7273
end
7374
command = "exiftool -Rating " .. RAF_filename
7475
dt.print_error(command)
75-
output = io.popen(command)
76+
output = dtsys.io_popen(command)
7677
local raf_result = output:read("*all")
7778
output:close()
7879
if string.len(raf_result) > 0 then

contrib/geoJSON_export.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ USAGE
3535
local dt = require "darktable"
3636
local du = require "lib/dtutils"
3737
local df = require "lib/dtutils.file"
38+
local dtsys = require "lib/dtutils.system"
3839
local gettext = dt.gettext.gettext
3940

4041
du.check_min_api_version("7.0.0", "geoJSON_export")
@@ -330,7 +331,7 @@ dt.preferences.register("geoJSON_export",
330331
_("opens the geoJSON file after the export with the standard program for geoJSON files"),
331332
false )
332333

333-
local handle = io.popen("xdg-user-dir DESKTOP")
334+
local handle = dtsys.io_popen("xdg-user-dir DESKTOP")
334335
local result = handle:read()
335336
handle:close()
336337
if (result == nil) then

contrib/geoToolbox.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ require "geoToolbox"
2828
local dt = require "darktable"
2929
local du = require "lib/dtutils"
3030
local df = require "lib/dtutils.file"
31+
local dtsys = require "lib/dtutils.system"
3132
local gettext = dt.gettext.gettext
3233

3334
du.check_min_api_version("7.0.0", "geoToolbox")
@@ -411,7 +412,7 @@ local function reverse_geocode()
411412
-- jq could be replaced with a Lua JSON parser
412413
startCommand = string.format("curl --silent \"https://api.mapbox.com/geocoding/v5/mapbox.places/%s,%s.json?types=%s&access_token=%s\" | jq '.features | .[0] | '.text''", lon1, lat1, types, tokan)
413414

414-
local handle = io.popen(startCommand)
415+
local handle = dtsys.io_popen(startCommand)
415416
local result = trim12(handle:read("*a"))
416417
handle:close()
417418

contrib/image_stack.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ local function list_files(search_string)
348348
search_string = string.gsub(search_string, "/", "\\\\")
349349
end
350350

351-
local f = io.popen(ls .. search_string)
351+
local f = dtsys.io_popen(ls .. search_string)
352352
if f then
353353
local found_file = f:read()
354354
while found_file do

contrib/image_time.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ local dt = require "darktable"
107107
local du = require "lib/dtutils"
108108
local df = require "lib/dtutils.file"
109109
local ds = require "lib/dtutils.string"
110+
local dtsys = require "lib/dtutils.system"
110111
local gettext = dt.gettext.gettext
111112

112113
local img_time = {}
@@ -225,7 +226,7 @@ local function get_image_taken_time(image)
225226

226227
local exiv2 = df.check_if_bin_exists("exiv2")
227228
if exiv2 then
228-
p = io.popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename)
229+
p = dtsys.io_popen(exiv2 .. " -K Exif.Image.DateTime " .. image.path .. PS .. image.filename)
229230
if p then
230231
for line in p:lines() do
231232
if string.match(line, "Exif.Image.DateTime") then
@@ -243,7 +244,7 @@ end
243244

244245
local function _get_windows_image_file_creation_time(image)
245246
local datetime = nil
246-
local p = io.popen("dir " .. image.path .. PS .. image.filename)
247+
local p = dtsys.io_popen("dir " .. image.path .. PS .. image.filename)
247248
if p then
248249
for line in p:lines() do
249250
if string.match(line, ds.sanitize_lua(image.filename)) then
@@ -264,7 +265,7 @@ end
264265

265266
local function _get_nix_image_file_creation_time(image)
266267
local datetime = nil
267-
local p = io.popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename)
268+
local p = dtsys.io_popen("ls -lL --time-style=full-iso " .. image.path .. PS .. image.filename)
268269
if p then
269270
for line in p:lines() do
270271
if string.match(line, ds.sanitize_lua(image.filename)) then

contrib/kml_export.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ if dt.configuration.running_os == "windows" then
343343
elseif dt.configuration.running_os == "macos" then
344344
defaultDir = os.getenv("HOME")
345345
else
346-
local handle = io.popen("xdg-user-dir DESKTOP")
346+
local handle = dsys.io_popen("xdg-user-dir DESKTOP")
347347
defaultDir = handle:read()
348348
handle:close()
349349
end

lib/dtutils.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ dtutils.libdoc.functions["check_max_api_version"] = {
8282
run against the current api version. This function is used when a part of the Lua API that
8383
the script relies on is removed. If the maximum api version is not met, then an
8484
error message is printed saying the script_name failed to load, then an error is thrown causing the
85-
program to stop executing.
86-
85+
program to stop executing.]],
8786
Return_Value = [[result - true if the maximum api version is available, false if not.]],
8887
Limitations = [[When using the default handler on a script being executed from the luarc file, the error thrown
8988
will stop the luarc file from executing any remaining statements. This limitation does not apply to script_manger.]],

lib/dtutils/file.lua

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ end
4242

4343
local function _win_os_execute(cmd)
4444
local result = nil
45-
local p = io.popen(cmd)
45+
local p = dsys.io_popen(cmd)
4646
local output = p:read("*a")
4747
p:close()
4848
if string.match(output, "true") then
@@ -94,7 +94,7 @@ dtutils_file.libdoc.functions["test_file"] = {
9494

9595
function dtutils_file.test_file(path, test)
9696
local cmd = "test -"
97-
local engine = os.execute
97+
local engine = dsys.os_execute
9898
local cmdstring = ""
9999

100100
if dt.configuration.running_os == "windows" then
@@ -167,7 +167,7 @@ local function _search_for_bin_windows(bin)
167167

168168
for _,arg in ipairs(args) do
169169
local cmd = "where " .. arg .. " " .. ds.sanitize(bin)
170-
local p = io.popen(cmd)
170+
local p = dsys.io_popen(cmd)
171171
local output = p:read("*a")
172172
p:close()
173173
local lines = du.split(output, "\n")
@@ -191,7 +191,7 @@ end
191191

192192
local function _search_for_bin_nix(bin)
193193
local result = false
194-
local p = io.popen("command -v " .. bin)
194+
local p = dsys.io_popen("command -v " .. bin)
195195
local output = p:read("*a")
196196
p:close()
197197
if string.len(output) > 0 then
@@ -220,7 +220,7 @@ local function _search_for_bin_macos(bin)
220220
search_start = "/Applications/" .. bin .. ".app"
221221
end
222222

223-
local p = io.popen("find " .. search_start .. " -type f -name " .. bin .. " -print")
223+
local p = dsys.io_popen("find " .. search_start .. " -type f -name " .. bin .. " -print")
224224
local output = p:read("*a")
225225
p:close()
226226
local lines = du.split(output, "\n")
@@ -445,7 +445,7 @@ function dtutils_file.check_if_file_exists(filepath)
445445
local result = false
446446
if (dt.configuration.running_os == 'windows') then
447447
filepath = string.gsub(filepath, '[\\/]+', '\\')
448-
local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')")
448+
local p = dsys.io_popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')")
449449
local ans = p:read("*all")
450450
p:close()
451451
if string.match(ans, "yes") then
@@ -456,7 +456,7 @@ function dtutils_file.check_if_file_exists(filepath)
456456
-- result = false
457457
-- end
458458
elseif (dt.configuration.running_os == "linux") then
459-
result = os.execute('test -e ' .. dtutils_file.sanitize_filename(filepath))
459+
result = dsys.os_execute('test -e ' .. dtutils_file.sanitize_filename(filepath))
460460
if not result then
461461
result = false
462462
end
@@ -522,9 +522,9 @@ function dtutils_file.file_copy(fromFile, toFile)
522522
local result = nil
523523
-- if cp exists, use it
524524
if dt.configuration.running_os == "windows" then
525-
result = os.execute('copy "' .. fromFile .. '" "' .. toFile .. '"')
525+
result = dsys.os_execute('copy "' .. fromFile .. '" "' .. toFile .. '"')
526526
elseif dtutils_file.check_if_bin_exists("cp") then
527-
result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'")
527+
result = dsys.os_execute("cp '" .. fromFile .. "' '" .. toFile .. "'")
528528
end
529529

530530
-- if cp was not present, or if cp failed, then a pure lua solution
@@ -575,7 +575,7 @@ function dtutils_file.file_move(fromFile, toFile)
575575
if not success then
576576
-- an error occurred, so let's try using the operating system function
577577
if dtutils_file.check_if_bin_exists("mv") then
578-
success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'")
578+
success = dsys.os_execute("mv '" .. fromFile .. "' '" .. toFile .. "'")
579579
end
580580
-- if the mv didn't exist or succeed, then...
581581
if not success then

lib/dtutils/system.lua

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
local dtutils_system = {}
22

33
local dt = require "darktable"
4+
local ds = require "lib/dtutils.string"
45

56
dtutils_system.libdoc = {
67
Name = [[dtutils.system]],
@@ -50,9 +51,9 @@ function dtutils_system.external_command(command)
5051
local result = nil
5152

5253
if dt.configuration.running_os == "windows" then
53-
result = dtutils_system.windows_command(command)
54+
result = dtutils_system.windows_command(ds.sanitize(command))
5455
else
55-
result = dt.control.execute(command)
56+
result = dt.control.execute(ds.sanitize(command))
5657
end
5758

5859
return result
@@ -77,15 +78,20 @@ dtutils_system.libdoc.functions["windows_command"] = {
7778
Copyright = [[]],
7879
}
7980

81+
local function quote_windows_command(command)
82+
return "\"" .. command .. "\""
83+
end
84+
8085
function dtutils_system.windows_command(command)
8186
local result = 1
8287

83-
local fname = dt.configuration.tmp_dir .. "/run_command.bat"
88+
local fname = ds.sanitize(dt.configuration.tmp_dir .. "/run_command.bat")
8489

8590
local file = io.open(fname, "w")
8691
if file then
8792
dt.print_log("opened file")
8893
command = string.gsub(command, "%%", "%%%%") -- escape % from windows shell
94+
command = quote_windows-command(command)
8995
file:write(command)
9096
file:close()
9197

@@ -129,4 +135,55 @@ function dtutils_system.launch_default_app(path)
129135
end
130136

131137

138+
dtutils_system.libdoc.functions["os_execute"] = {
139+
Name = [[os_execute]],
140+
Synopsis = [[wrapper around the lua os.execute function]],
141+
Usage = [[local dsys = require "lib/dtutils.file"
142+
143+
result = dsys.os_execute(cmd)
144+
cmd - string - a command to execute on the operating system]],
145+
Description = [[os_execute wraps the lua os.execute system call to provide
146+
correct sanitization of windows commands]],
147+
Return_Value = [[see the lua os.execute documentation]],
148+
Limitations = [[]],
149+
Example = [[]],
150+
See_Also = [[]],
151+
Reference = [[]],
152+
License = [[]],
153+
Copyright = [[]],
154+
}
155+
156+
function dtutils_system.os_execute(cmd)
157+
if dt.configuration.running_os == "windows" then
158+
cmd = quote_windows_command(cmd)
159+
end
160+
return os.execute(cmd)
161+
end
162+
163+
dtutils_system.libdoc.functions["io_popen"] = {
164+
Name = [[io_popen]],
165+
Synopsis = [[wrapper around the lua io.popen function]],
166+
Usage = [[local dsys = require "lib/dtutils.file"
167+
168+
result = dsys.io_popen(cmd)
169+
cmd - string - a command to execute and attach to]],
170+
Description = [[io_popen wraps the lua io.popen system call to provide
171+
correct sanitization of windows commands]],
172+
Return_Value = [[see the lua io.popen documentation]],
173+
Limitations = [[]],
174+
Example = [[]],
175+
See_Also = [[]],
176+
Reference = [[]],
177+
License = [[]],
178+
Copyright = [[]],
179+
}
180+
181+
function dtutils_system.io_popen(cmd)
182+
if dt.configuration.running_os == "windows" then
183+
cmd = quote_windows_command(cmd)
184+
end
185+
return io.popen(cmd)
186+
end
187+
188+
132189
return dtutils_system

official/enfuse.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ if enfuse_installed then
116116

117117
local version = nil
118118

119-
local p = io.popen(enfuse_installed .. " --version")
119+
local p = dtsys.io_popen(enfuse_installed .. " --version")
120120
local f = p:read("all")
121121
p:close()
122122
version = string.match(f, "enfuse (%d.%d)")

tools/executable_manager.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
local dt = require "darktable"
3232
local du = require "lib/dtutils"
3333
local df = require "lib/dtutils.file"
34+
local dtsys = require "lib/dtutils.system"
3435

3536
du.check_min_api_version("7.0.0", "executable_manager")
3637

@@ -75,7 +76,7 @@ local function grep(file, pattern)
7576
if dt.configuration.running_os == "windows" then
7677
-- use find to get the matches
7778
local command = "\\windows\\system32\\find.exe " .. "\"" .. pattern .. "\"" .. " " .. file
78-
local f = io.popen(command)
79+
local f = dtsys.io_popen(command)
7980
local output = f:read("all")
8081
f:close()
8182
-- strip out the first line
@@ -84,7 +85,7 @@ local function grep(file, pattern)
8485
else
8586
-- use grep and just return the answers
8687
local command = "grep " .. pattern .. " " .. file
87-
local f = io.popen(command)
88+
local f = dtsys.io_popen(command)
8889
local output = f:read("all")
8990
f:close()
9091
result = du.split(output, "\n")

0 commit comments

Comments
 (0)