Skip to content

Commit

Permalink
Preserve information whether attachments are executable.
Browse files Browse the repository at this point in the history
This is relevant for testing tools which are often uploaded as
attachments for interactive problems. When we download the samples (via
the web interface or API), we should mark these files as executable iff
they were executable when uploading.
  • Loading branch information
meisterT committed Sep 21, 2024
1 parent 95e6373 commit 270975d
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
31 changes: 31 additions & 0 deletions webapp/migrations/Version20240917113927.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20240917113927 extends AbstractMigration
{
public function getDescription(): string
{
return 'Adding executable bit to problem attachments.';
}

public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE problem_attachment_content ADD is_executable TINYINT(1) DEFAULT 0 NOT NULL COMMENT \'Whether this file gets an executable bit.\'');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE problem_attachment_content DROP is_executable');
}

public function isTransactional(): bool
{
return false;
}
}
16 changes: 16 additions & 0 deletions webapp/src/Entity/ProblemAttachmentContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;

#[ORM\Entity]
#[ORM\Table(options: [
Expand All @@ -25,6 +26,10 @@ class ProblemAttachmentContent
#[ORM\Column(type: 'blobtext', options: ['comment' => 'Attachment content'])]
private string $content;

#[ORM\Column(options: ['comment' => 'Whether this file gets an executable bit.', 'default' => 0])]
#[Serializer\Exclude]
private bool $isExecutable = false;

public function getAttachment(): ProblemAttachment
{
return $this->attachment;
Expand All @@ -48,4 +53,15 @@ public function setContent(string $content): self

return $this;
}

public function setIsExecutable(bool $isExecutable): ProblemAttachmentContent
{
$this->isExecutable = $isExecutable;
return $this;
}

public function isExecutable(): bool
{
return $this->isExecutable;
}
}
8 changes: 8 additions & 0 deletions webapp/src/Service/DOMJudgeService.php
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,14 @@ public function getSamplesZipForContest(Contest $contest): StreamedResponse
foreach ($problem->getProblem()->getAttachments() as $attachment) {
$filename = sprintf('%s/attachments/%s', $problem->getShortname(), $attachment->getName());
$zip->addFromString($filename, $attachment->getContent()->getContent());
if ($attachment->getContent()->isExecutable()) {
// 100755 = regular file, executable
$zip->setExternalAttributesName(
$filename,
ZipArchive::OPSYS_UNIX,
octdec('100755') << 16
);
}
}
}

Expand Down
16 changes: 15 additions & 1 deletion webapp/src/Service/ImportProblemService.php
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,14 @@ public function importZippedProblem(
continue;
}

// In doubt make files executable, but try to read it from the zip file.
$executableBit = true;
if ($zip->getExternalAttributesIndex($j, $opsys, $attr)
&& $opsys==ZipArchive::OPSYS_UNIX
&& (($attr >> 16) & 0100) === 0) {
$executableBit = false;
}

$name = basename($filename);

$fileParts = explode('.', $name);
Expand All @@ -558,6 +566,10 @@ public function importZippedProblem(
$messages['info'][] = sprintf("Updated attachment '%s'", $name);
$numAttachments++;
}
if ($executableBit !== $attachmentContent->isExecutable()) {
$attachmentContent->setIsExecutable($executableBit);
$messages['info'][] = sprintf("Updated executable bit of attachment '%s'", $name);
}
} else {
$attachment = new ProblemAttachment();
$attachmentContent = new ProblemAttachmentContent();
Expand All @@ -567,7 +579,9 @@ public function importZippedProblem(
->setType($type)
->setContent($attachmentContent);

$attachmentContent->setContent($content);
$attachmentContent
->setContent($content)
->setIsExecutable($executableBit);

$this->em->persist($attachment);

Expand Down

0 comments on commit 270975d

Please sign in to comment.