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 17, 2024
1 parent f30e6d3 commit b2ef223
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
15 changes: 15 additions & 0 deletions webapp/src/Entity/ProblemAttachmentContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,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]

Check failure on line 29 in webapp/src/Entity/ProblemAttachmentContent.php

View workflow job for this annotation

GitHub Actions / phpstan

Attribute class App\Entity\Serializer\Exclude does not exist.
private bool $isExecutable = false;

public function getAttachment(): ProblemAttachment
{
return $this->attachment;
Expand All @@ -48,4 +52,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 b2ef223

Please sign in to comment.