Skip to content

Commit

Permalink
Permissions support...let mkdir set permissions, and let config file …
Browse files Browse the repository at this point in the history
…specify

 file/dir permissions.
  • Loading branch information
icculus committed May 18, 2007
1 parent 02ecac4 commit 09cbf34
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 16 deletions.
43 changes: 43 additions & 0 deletions docs.txt
Expand Up @@ -157,6 +157,7 @@ Here are the elements, and the attributes they can possess.
mustBeFunction: Error if isn't a function (can be C or Lua).
mustBeNumber: Error if isn't a number.
mustBeUrl: Error if isn't a string that matches the regexp "^.+://.-/.*".
mustBePerms: Error if isn't a valid permissions string for the platform.
mustBeStringOrTableOfStrings: Error if isn't a string or an array of strings.

Attributes that aren't explicitly specified take on their default value. In
Expand Down Expand Up @@ -576,6 +577,20 @@ Here are the elements, and the attributes they can possess.
return dest -- everything else can go through as-is.
end

Filters can optionally return a second argument, a string, that defines
the destination file's permissions. This can be omitted, or nil, to use
the default permissions:

filter = function(dest)
if dest == "mygame-binary" then
return dest, "0755" -- make sure it's executable.
end
return dest -- everything else just goes through as-is.
end

Please see the documentation for Setup.File's "permissions" attribute for
further discussion.


allowoverwrite (no default, mustBeBool)

Expand All @@ -587,6 +602,34 @@ Here are the elements, and the attributes they can possess.
They are deleted only after a successful install.


permissions (no default, mustBePerms)

Override the permissions that these files will be created with. This is
a string for future expansion (non-Unix systems, extended attributes, etc),
and since Lua does not have syntax for specifying octal numbers directly.

Currently this string maps to Unix permissions as an octal number:
"0644" would be read/write access for the user, and read-only for the
group and everyone else.

If not specified, the permissions will be set to whatever is already
associated with the file (such as the Unix permissions in a .tar file's
entry).

Please note that files coming from a real filesystem will have their
defaults overridden by the installer (to "0644"), since operating systems
tend to report every file on a CD-ROMs as read-only and executable on some
Unix systems. Plan accordingly.

You can return a permissions string as the second value from your filter
function as well, which may be more efficient if you only need to change
a few files, as each Setup.File has to iterate the whole archive, or need
to adjust permissions in only a portion of a downloaded archive. This
attribute applies permissions to ever installed file through this element.
If this attribute is set and the filter returns a non-nil permission, the
filter takes precedence.


Add any localized strings:

If you added strings to the installer or your config file that you want
Expand Down
4 changes: 2 additions & 2 deletions fileio.c
Expand Up @@ -387,11 +387,11 @@ static const MojoArchiveEntry *MojoArchive_dir_enumNext(MojoArchive *ar)
{
ar->prevEnum.filesize = statbuf.st_size;

// !!! FIXME: not sure this is the best thing.
// We currently force the perms from physical files, since CDs on
// Linux tend to mark every files as executable and read-only. If you
// want to install something with specific permissions, wrap it in a
// tarball or chmod it from a postinstall hook in your config file.
// tarball, or use Setup.File.permissions, or return a permissions
// string from Setup.File.filter.
//ar->prevEnum.perms = statbuf.st_mode;
ar->prevEnum.perms = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

Expand Down
37 changes: 34 additions & 3 deletions lua_glue.c
Expand Up @@ -673,18 +673,37 @@ static int luahook_writefile(lua_State *L)
{
MojoArchive *archive = (MojoArchive *) lua_touserdata(L, 1);
const char *path = luaL_checkstring(L, 2);
uint16 perms = archive->prevEnum.perms;
boolean retval = false;
MojoInput *in = archive->openCurrentEntry(archive);
if (in != NULL)
{
retval = MojoInput_toPhysicalFile(in, path, archive->prevEnum.perms,
writeCallback, L);
if (!lua_isnil(L, 3))
{
boolean valid = false;
const char *permstr = luaL_checkstring(L, 3);
perms = MojoPlatform_makePermissions(permstr, &valid);
if (!valid)
fatal(_("BUG: '%s' is not a valid permission string"), permstr);
} // if
retval = MojoInput_toPhysicalFile(in, path, perms, writeCallback, L);
} // if

return retvalBoolean(L, retval);
} // luahook_writefile


static int luahook_isvalidperms(lua_State *L)
{
boolean valid = false;
const char *permstr = NULL;
if (!lua_isnil(L, 1))
permstr = luaL_checkstring(L, 1);
MojoPlatform_makePermissions(permstr, &valid);
return retvalBoolean(L, valid);
} // luahook_isvalidperms


static int luahook_download(lua_State *L)
{
boolean retval = false;
Expand Down Expand Up @@ -811,7 +830,18 @@ static int luahook_platform_symlink(lua_State *L)
static int luahook_platform_mkdir(lua_State *L)
{
const char *dir = luaL_checkstring(L, 1);
return retvalBoolean(L, MojoPlatform_mkdir(dir));
uint16 perms = 0;
if (lua_isnil(L, 2))
perms = MojoPlatform_defaultDirPerms();
else
{
boolean valid = false;
const char *permstr = luaL_checkstring(L, 2);
perms = MojoPlatform_makePermissions(permstr, &valid);
if (!valid)
fatal(_("BUG: '%s' is not a valid permission string"), permstr);
} // if
return retvalBoolean(L, MojoPlatform_mkdir(dir, perms));
} // luahook_platform_mkdir


Expand Down Expand Up @@ -1330,6 +1360,7 @@ boolean MojoLua_initLua(void)
set_cfunc(luaState, luahook_wildcardmatch, "wildcardmatch");
set_cfunc(luaState, luahook_truncatenum, "truncatenum");
set_cfunc(luaState, luahook_date, "date");
set_cfunc(luaState, luahook_isvalidperms, "isvalidperms");

// Set some information strings...
lua_newtable(luaState);
Expand Down
16 changes: 15 additions & 1 deletion platform.h
Expand Up @@ -47,7 +47,7 @@ char *MojoPlatform_realpath(const char *path);
boolean MojoPlatform_symlink(const char *src, const char *dst);

// !!! FIXME: comment me.
boolean MojoPlatform_mkdir(const char *path);
boolean MojoPlatform_mkdir(const char *path, uint16 perms);

// Move a file to a new name. This has to be a fast (if not atomic) operation,
// so if it would require a legitimate copy to another filesystem or device,
Expand All @@ -73,6 +73,20 @@ boolean MojoPlatform_chmod(const char *fname, uint16 p);
// !!! FIXME: comment me.
char *MojoPlatform_findMedia(const char *uniquefile);

// Convert a string into a permissions bitmask. On Unix, this is currently
// expected to be an octal string like "0755", but may except other forms
// in the future, and other platforms may need to interpret permissions
// differently. (str) may be NULL for defaults, and is considered valid.
// If (str) is not valid, return a reasonable default and set (*valid) to
// false. Otherwise, set (*valid) to true and return the converted value.
uint16 MojoPlatform_makePermissions(const char *str, boolean *valid);

// Return a default, sane set of permissions for a newly-created file.
uint16 MojoPlatform_defaultFilePerms(void);

// Return a default, sane set of permissions for a newly-created directory.
uint16 MojoPlatform_defaultDirPerms(void);

// Wrappers for Unix dlopen/dlsym/dlclose, sort of. Instead of a filename,
// these take a memory buffer for the library. If you can't load this
// directly in RAM, the platform should write it to a temporary file first,
Expand Down
35 changes: 33 additions & 2 deletions platform_unix.c
Expand Up @@ -482,10 +482,10 @@ boolean MojoPlatform_symlink(const char *src, const char *dst)
} // MojoPlatform_symlink


boolean MojoPlatform_mkdir(const char *path)
boolean MojoPlatform_mkdir(const char *path, uint16 perms)
{
// !!! FIXME: error if already exists?
return (mkdir(path, 0755) == 0);
return (mkdir(path, perms) == 0);
} // MojoPlatform_mkdir


Expand Down Expand Up @@ -544,6 +544,37 @@ boolean MojoPlatform_perms(const char *fname, uint16 *p)
} // MojoPlatform_perms


uint16 MojoPlatform_defaultFilePerms(void)
{
return 0644;
} // MojoPlatform_defaultFilePerms


uint16 MojoPlatform_defaultDirPerms(void)
{
return 0755;
} // MojoPlatform_defaultDirPerms


uint16 MojoPlatform_makePermissions(const char *str, boolean *_valid)
{
uint16 retval = 0644;
boolean valid = true;
if (str != NULL)
{
char *endptr = NULL;
long strval = strtol(str, &endptr, 8);
// complete string was a valid number?
valid = ((*endptr == '\0') && (strval >= 0) && (strval <= 0xFFFF));
if (valid)
retval = (uint16) strval;
} // if

*_valid = valid;
return retval;
} // MojoPlatform_makePermissions


boolean MojoPlatform_chmod(const char *fname, uint16 p)
{
return (chmod(fname, p) != -1);
Expand Down
8 changes: 8 additions & 0 deletions scripts/mojosetup_init.lua
Expand Up @@ -128,6 +128,7 @@ Setup = {}

local function schema_assert(test, fnname, elem, errstr)
if not test then
-- !!! FIXME: error()? localization?
error(fnname .. "::" .. elem .. " " .. errstr .. ".", 0)
end
end
Expand Down Expand Up @@ -209,6 +210,12 @@ local function mustBeUrl(fnname, elem, val)
end
end

local function mustBePerms(fnname, elem, val)
mustBeString(fnname, elem, val)
local valid = MojoSetup.isvalidperms(val)
schema_assert(valid, fnname, elem, "Permission string is invalid")
end

local function sanitize(fnname, tab, elems)
mustBeTable(fnname, "", tab)
tab._type_ = string.lower(fnname) .. "s"; -- "Eula" becomes "eulas".
Expand Down Expand Up @@ -412,6 +419,7 @@ function Setup.File(tab)
{ "wildcards", nil, mustBeStringOrTableOfStrings },
{ "filter", nil, mustBeFunction },
{ "allowoverwrite", nil, mustBeBool },
{ "permissions", nil, mustBePerms },
})
end

Expand Down
22 changes: 14 additions & 8 deletions scripts/mojosetup_mainline.lua
Expand Up @@ -226,7 +226,7 @@ local function drill_for_archive(archive, path, arclist)
end


local function install_file(path, archive, file, option)
local function install_file(path, archive, file, option, perms)
-- Upvalued so we don't look these up each time...
local fname = string.gsub(path, "^.*/", "", 1) -- chop the dirs off...
local ptype = _("Installing") -- !!! FIXME: localization.
Expand All @@ -245,7 +245,7 @@ local function install_file(path, archive, file, option)
end

MojoSetup.installed_files[#MojoSetup.installed_files+1] = path
if not MojoSetup.writefile(archive, path, callback) then
if not MojoSetup.writefile(archive, path, perms, callback) then
-- !!! FIXME: formatting!
if not keepgoing then
MojoSetup.logerror("User cancelled install during file write.")
Expand All @@ -270,9 +270,9 @@ local function install_symlink(path, lndest)
end


local function install_directory(path)
local function install_directory(path, perms)
MojoSetup.installed_files[#MojoSetup.installed_files+1] = path
if not MojoSetup.platform.mkdir(path) then
if not MojoSetup.platform.mkdir(path, perms) then
-- !!! FIXME: formatting
MojoSetup.logerror("Failed to create dir '" .. path .. "'")
MojoSetup.fatal(_("mkdir failed"))
Expand All @@ -291,7 +291,7 @@ local function install_parent_dirs(path)
if item ~= "" then
fullpath = fullpath .. "/" .. item
if not MojoSetup.platform.exists(fullpath) then
install_directory(fullpath)
install_directory(fullpath, nil)
end
end
end
Expand Down Expand Up @@ -361,18 +361,24 @@ local function install_archive_entry(archive, ent, file, option)
dest = dest .. "/" .. entdest
end

local perms = file.permissions -- may be nil

if file.filter ~= nil then
dest = file.filter(dest)
local filterperms
dest, filterperms = file.filter(dest)
if filterperms ~= nil then
perms = filterperms
end
end

if dest ~= nil then -- Only install if file wasn't filtered out
dest = MojoSetup.destination .. "/" .. dest
if permit_write(dest, ent, file) then
install_parent_dirs(dest)
if ent.type == "file" then
install_file(dest, archive, file, option)
install_file(dest, archive, file, option, perms)
elseif ent.type == "dir" then
install_directory(dest)
install_directory(dest, perms)
elseif ent.type == "symlink" then
install_symlink(dest, ent.linkdest)
else -- !!! FIXME: device nodes, etc...
Expand Down

0 comments on commit 09cbf34

Please sign in to comment.