hokey primitive to create temporary file

The trouble with os.tmpname() is that it always creates in /tmp.
If /tmp is in a different volume from our real filename, os.rename()
will fail.

This new primitive doesn't support primitive paths yet.

I'm also again nervous about the security implications of my whole
approach. What if we create an inner function called start_writing?
Would we be able to do anything inside it? I'm starting to suspect this
whole approach of going by caller name is broken. An app could also
create inner functions called 'main'..
This commit is contained in:
Kartik K. Agaram 2022-03-07 19:14:02 -08:00
parent 88827db20d
commit a0674f7b85
2 changed files with 26 additions and 1 deletions

View File

@ -23,8 +23,11 @@ end
-- indicate you're done writing by calling :close()
-- file will not be externally visible until :close()
function start_writing(fs, filename)
if filename == nil then
error('start_writing requires two arguments: a file-system (nil for real disk) and a filename')
end
local result = task.Channel:new()
local initial_filename = os.tmpname()
local initial_filename = temporary_filename_in_same_volume(filename)
local outfile = io.open(initial_filename, 'w')
if outfile == nil then return nil end
result.close = function()
@ -36,6 +39,25 @@ function start_writing(fs, filename)
return result
end
function temporary_filename_in_same_volume(filename)
-- opening in same directory will hopefully keep it on the same volume,
-- so that a future rename works
local i = 1
while true do
temporary_filename = 'teliva_temp_'..filename..'_'..i
if io.open(temporary_filename) == nil then
-- file doesn't exist yet; create a placeholder and return it
local handle = io.open(temporary_filename, 'w')
if handle == nil then
error("this is unexpected; I can't create temporary files..")
end
handle:close()
return temporary_filename
end
i = i+1
end
end
function writing_task(outfile, chanin)
while true do
local line = chanin:recv()

View File

@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#define liolib_c
#define LUA_LIB
@ -139,6 +140,8 @@ static int io_open (lua_State *L) {
const char *caller = get_caller(L);
if (file_operation_permitted(caller, filename, mode))
*pf = fopen(filename, mode);
else if (is_equal(caller, "temporary_filename_in_same_volume"))
*pf = fopen(filename, mode);
else if (is_equal(caller, "start_writing") || is_equal(caller, "start_reading")) {
caller = get_caller_of_caller(L);
if (file_operation_permitted(caller, filename, mode))