Skip to content
This repository has been archived by the owner on Oct 8, 2020. It is now read-only.

Commit

Permalink
MInimal extension support for index file parsing.
Browse files Browse the repository at this point in the history
Skip all optional extensions; error out if any required extensions are present.

Closes #67. Introduces #172 (required extensions unsupported).
  • Loading branch information
scouten committed Sep 22, 2019
1 parent 6e88c21 commit 20e1a57
Showing 1 changed file with 40 additions and 8 deletions.
48 changes: 40 additions & 8 deletions lib/xgit/repository/working_tree/parse_index_file.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ defmodule Xgit.Repository.WorkingTree.ParseIndexFile do

import Xgit.Util.ForceCoverage

require Logger

alias Xgit.Core.DirCache
alias Xgit.Core.DirCache.Entry, as: DirCacheEntry
alias Xgit.Core.ObjectId
Expand All @@ -23,7 +25,7 @@ defmodule Xgit.Repository.WorkingTree.ParseIndexFile do
| :invalid_format
| :unsupported_version
| :too_many_entries
| :extensions_not_supported
| :unsupported_extension
| :sha_hash_mismatch
| File.posix()

Expand All @@ -49,9 +51,10 @@ defmodule Xgit.Repository.WorkingTree.ParseIndexFile do
entries. This is an arbitrary limit to guard against malformed files and to
prevent overconsumption of memory. With experience, it could be revisited.
`{:error, :extensions_not_supported}` if any index file extensions are present.
Parsing extensions is not yet supported. (See
[issue #67](https://github.com/elixir-git/xgit/issues/67).)
`{:error, :unsupported_extension}` if any index file extensions are present
that can not be parsed. Optional extensions will be skipped, but no required
extensions are understood at this time. (See
[issue #172](https://github.com/elixir-git/xgit/issues/172).)
`{:error, :sha_hash_mismatch}` if the SHA-1 hash written at the end of the file
does not match the file contents.
Expand All @@ -67,9 +70,7 @@ defmodule Xgit.Repository.WorkingTree.ParseIndexFile do
{:entry_count, read_uint32(iodevice)},
{:entries, entries} when is_list(entries) <-
{:entries, read_entries(iodevice, version, entry_count)},
{:extensions, :eof} <- {:extensions, IO.binread(iodevice, 1)},
# TO DO: Parse extensions. For now, error out if any are present.
# https://github.com/elixir-git/xgit/issues/67
{:extensions, :ok} <- {:extensions, read_extensions(iodevice)},
{:sha_valid?, true} <- {:sha_valid?, TrailingHashDevice.valid_hash?(iodevice)} do
cover {:ok,
%DirCache{
Expand All @@ -84,7 +85,7 @@ defmodule Xgit.Repository.WorkingTree.ParseIndexFile do
{:entry_count, :invalid} -> cover {:error, :invalid_format}
{:entry_count, _} -> cover {:error, :too_many_entries}
{:entries, _} -> cover {:error, :invalid_format}
{:extensions, _} -> cover {:error, :extensions_not_supported}
{:extensions, error} -> cover {:error, error}
{:sha_valid?, _} -> cover {:error, :sha_hash_mismatch}
end
end
Expand Down Expand Up @@ -154,6 +155,37 @@ defmodule Xgit.Repository.WorkingTree.ParseIndexFile do
defp valid_entry?(%DirCacheEntry{}), do: cover(true)
defp valid_entry?(_), do: cover(false)

defp read_extensions(iodevice) do
case IO.binread(iodevice, 1) do
:eof -> :ok
[char] when char >= ?A and char <= ?Z -> read_optional_extension(iodevice, char)
[char] -> read_required_extension(iodevice, char)
end
end

defp read_optional_extension(iodevice, char) do
signature = [char | IO.binread(iodevice, 3)]
length = read_uint32(iodevice)

Logger.info(fn ->
"skipping extension with signature #{inspect(signature)}, #{length} bytes"
end)

IO.binread(iodevice, length)
read_extensions(iodevice)
end

defp read_required_extension(iodevice, char) do
signature = [char | IO.binread(iodevice, 3)]
length = read_uint32(iodevice)

Logger.info(fn ->
"don't know how to read required extension with signature #{inspect(signature)}, #{length} bytes"
end)

:unsupported_extension
end

defp read_uint16(iodevice) do
case IO.binread(iodevice, 2) do
x when is_binary(x) and byte_size(x) == 2 ->
Expand Down

0 comments on commit 20e1a57

Please sign in to comment.