mirror of
https://github.com/fmang/opustags.git
synced 2024-11-10 07:27:22 +01:00
proper permissions setting on output files
This commit is contained in:
parent
4de428bf33
commit
ea4d74d844
@ -13,6 +13,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
ot::status ot::partial_file::open(const char* destination)
|
||||
@ -33,11 +34,45 @@ ot::status ot::partial_file::open(const char* destination)
|
||||
return st::ok;
|
||||
}
|
||||
|
||||
static mode_t get_umask()
|
||||
{
|
||||
// libc doesn’t seem to provide a way to get umask without changing it, so we need this workaround.
|
||||
// https://www.gnu.org/software/libc/manual/html_node/Setting-Permissions.html
|
||||
mode_t mask = umask(0);
|
||||
umask(mask);
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try reproducing the file permissions of file `source` onto file `dest`. If
|
||||
* this fails for whatever reason, print a warning and leave the current
|
||||
* permissions. When the source doesn’t exist, use the default file creation
|
||||
* permissions according to umask.
|
||||
*/
|
||||
static void copy_permissions(const char* source, const char* dest)
|
||||
{
|
||||
mode_t target_mode;
|
||||
struct stat source_stat;
|
||||
if (stat(source, &source_stat) == 0) {
|
||||
// We could technically preserve a bit more than that but who
|
||||
// would ever need S_ISUID and friends on an Opus file?
|
||||
target_mode = source_stat.st_mode & 0777;
|
||||
} else if (errno == ENOENT) {
|
||||
target_mode = 0666 & ~get_umask();
|
||||
} else {
|
||||
fprintf(stderr, "warning: Could not read mode of %s: %s\n", source, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (chmod(dest, target_mode) == -1)
|
||||
fprintf(stderr, "warning: Could not set mode of %s: %s\n", dest, strerror(errno));
|
||||
}
|
||||
|
||||
ot::status ot::partial_file::commit()
|
||||
{
|
||||
if (file == nullptr)
|
||||
return st::ok;
|
||||
file.reset();
|
||||
copy_permissions(final_name.c_str(), temporary_name.c_str());
|
||||
if (rename(temporary_name.c_str(), final_name.c_str()) == -1)
|
||||
return {st::standard_error,
|
||||
"Could not move the result file '" + temporary_name + "' to '" +
|
||||
|
@ -4,7 +4,7 @@ use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use Test::More tests => 34;
|
||||
use Test::More tests => 37;
|
||||
|
||||
use Digest::MD5;
|
||||
use File::Basename;
|
||||
@ -101,8 +101,11 @@ encoder=Lavc58.18.100 libopus
|
||||
EOF
|
||||
|
||||
unlink('out.opus');
|
||||
my $previous_umask = umask(0022);
|
||||
is_deeply(opustags(qw(gobble.opus -o out.opus)), ['', '', 0], 'copy the file without changes');
|
||||
is(md5('out.opus'), '111a483596ac32352fbce4d14d16abd2', 'the copy is faithful');
|
||||
is((stat 'out.opus')[2] & 0777, 0644, 'apply umask on new files');
|
||||
umask($previous_umask);
|
||||
|
||||
# empty out.opus
|
||||
{ my $fh; open($fh, '>', 'out.opus') and close($fh) or die }
|
||||
@ -113,13 +116,17 @@ is(md5('out.opus'), 'd41d8cd98f00b204e9800998ecf8427e', 'the output wasn\'t writ
|
||||
|
||||
is_deeply(opustags(qw(gobble.opus -o /dev/null)), ['', '', 0], 'write to /dev/null');
|
||||
|
||||
chmod(0604, 'out.opus');
|
||||
is_deeply(opustags(qw(gobble.opus -o out.opus --overwrite)), ['', '', 0], 'overwrite');
|
||||
is(md5('out.opus'), '111a483596ac32352fbce4d14d16abd2', 'successfully overwritten');
|
||||
is((stat 'out.opus')[2] & 0777, 0604, 'overwriting preserves output file\'s mode');
|
||||
|
||||
chmod(0700, 'out.opus');
|
||||
is_deeply(opustags(qw(--in-place out.opus -a A=B --add=A=C --add), "TITLE=Foo Bar",
|
||||
qw(--delete A --add TITLE=七面鳥 --set encoder=whatever -s 1=2 -s X=1 -a X=2 -s X=3)),
|
||||
['', '', 0], 'complex tag editing');
|
||||
is(md5('out.opus'), '66780307a6081523dc9040f3c47b0448', 'check the footprint');
|
||||
is((stat 'out.opus')[2] & 0777, 0700, 'in-place editing preserves file mode');
|
||||
|
||||
is_deeply(opustags('out.opus'), [<<'EOF', '', 0], 'check the tags written');
|
||||
A=B
|
||||
|
Loading…
Reference in New Issue
Block a user