{"id":25427605,"url":"https://github.com/lefucjusz/tarchivist","last_synced_at":"2026-07-01T01:31:50.240Z","repository":{"id":177421100,"uuid":"544024742","full_name":"Lefucjusz/tarchivist","owner":"Lefucjusz","description":"A small, simple tar library implementation written in ANSI C. Based on rxi's microtar.","archived":false,"fork":false,"pushed_at":"2022-10-15T07:33:03.000Z","size":52,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-29T09:41:59.127Z","etag":null,"topics":["ansi","archive","c","library","tar","tarball"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Lefucjusz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-10-01T12:47:11.000Z","updated_at":"2023-12-10T09:33:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"695c019e-5a35-45f7-b406-ede651228aa6","html_url":"https://github.com/Lefucjusz/tarchivist","commit_stats":null,"previous_names":["lefucjusz/tarchivist"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Lefucjusz/tarchivist","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lefucjusz%2Ftarchivist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lefucjusz%2Ftarchivist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lefucjusz%2Ftarchivist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lefucjusz%2Ftarchivist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lefucjusz","download_url":"https://codeload.github.com/Lefucjusz/tarchivist/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lefucjusz%2Ftarchivist/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34989787,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansi","archive","c","library","tar","tarball"],"created_at":"2025-02-17T01:09:02.020Z","updated_at":"2026-07-01T01:31:49.781Z","avatar_url":"https://github.com/Lefucjusz.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\r\n# tarchivist\r\nA small, simple tar library implementation based on rxi's [microtar](https://github.com/rxi/microtar).  \r\nThe library consists of only two files - `tarchivist.c` and `tarchivist.h` - and is written in ANSI C, what makes it easy to integrate into a wide variety of projects.\r\n\r\n## Functionalities\r\n* Creating, writing and appending files to the tar archives\r\n* Reading file information from the tar archives\r\n* Reading file contents from the tar archives\r\n* Searching for the file with a given name in the tar archive\r\n* POSIX.1-1988 (*UStar*) tar header compliance\r\n* Proper archive finalizing mechanism\r\n* Custom stream interface\r\n\r\n## Examples\r\nThe following examples presenting the usage of the library have been included:\r\n* *read_demo* - presents the functionalities of reading the tar file;\r\n* *write_demo* - presents the functionalities of creating and writing the tar file;\r\n* *packer* - implements very simple *tar*-like utility that can perform packing and unpacking of an archive;\r\n* *packer-custom-stream* - presents how to use custom stream interface; apart from that has the same functionality as packer.\r\n\r\n### Running the examples\r\nThe examples use *POSIX* calls and libraries, so they have to be compiled under the environment that supports them.\r\n#### Clone the repo\r\n```shell\r\ngit clone https://github.com/Lefucjusz/tarchivist\r\n```\r\nor:\r\n```shell\r\ngit clone git@github.com:Lefucjusz/tarchivist.git\r\n```\r\n#### Build and run the desired example\r\n```shell\r\ncd tarchivist\r\n```\r\n##### Build all\r\n```shell\r\nmake\r\n```\r\n##### Build and run *read-demo*\r\n```shell\r\nmake read-demo\r\ncd build/bin\r\n./read-demo\r\n```\r\n##### Build and run *write-demo*\r\n```shell\r\nmake write-demo\r\ncd build/bin\r\n./write-demo\r\n```\r\n##### Build *packer*\r\n```shell\r\nmake packer\r\n```\r\n##### Run *packer* in pack mode\r\n`````shell\r\ncd build/bin\r\n./packer -p -s some_folder -d archive_to_pack_the_folder_to.tar\r\n`````\r\n\r\n##### Run *packer* in unpack mode\r\n`````shell\r\ncd build/bin\r\n./packer -u -s some_archive.tar -d folder_to_unpack_the_archive_to\r\n`````\r\n\r\n##### Build *packer*'s debug version (with *-Og* and *-ggdb3* flags) \r\n```shell\r\nmake packer-debug\r\n```\r\n\r\n##### Build *packer-custom-stream*\r\n```shell\r\nmake packer-custom-stream\r\n```\r\n\r\n## Custom stream interface\r\nBy default, the library reads and writes to a standard file using `stdio` file handling functions. It is, however, possible to initialize the `tarchivist_t` struct with custom stream callbacks and stream pointer to operate on something different than a file.\r\n#### Callbacks that have to be provided to read an archive from a stream\r\n* `int seek(tarchivist_t *tar, long offset, int whence) - sets the position of the stream cursor`\r\n* `long tell(tarchivist_t *tar) - gets the current position of the stream cursor`\r\n* `int read(tarchivist_t *tar, unsigned size, void *data) - reads 'size' bytes from the stream into the 'data'`\r\n* `int close(tarchivist_t *tar) - closes the stream`\r\n\r\n#### Callbacks that have to be provided to write an archive to a stream\r\n* `int seek(tarchivist_t *tar, long offset, int whence) - sets the position of the stream cursor`\r\n* `long tell(tarchivist_t *tar) - gets the current position of the stream cursor`\r\n* `int read(tarchivist_t *tar, unsigned size, void *data) - reads 'size' bytes from the stream into the 'data'`\r\n* `int write(tarchivist_t *tar, unsigned size, const void *data) - writes 'size' bytes from the 'data' to the stream`\r\n* `int close(tarchivist_t *tar) - closes the stream`\r\n\r\nAll callbacks should return `TARCHIVIST_SUCCESS` on success and negative return code on failure, except for `tell`, which should return current position of stream cursor on success and negative return code on failure.\r\n\r\nWhen operating the library with a custom stream, the `tarchivist_open` function shall not be used. The stream shall be opened manually and all unused `tarchivist_t` struct fields shall be zero-filled.\r\n\r\n## Things to improve\r\n\r\n### Closing record detection\r\nThe algorithm detecting whether an archive is finalized (i.e. contains two null records at the end) is very straightforward. Only two conditions are checked:\r\n* if the size of an archive file is at least 1024 bytes (the size of two null records);\r\n* if the last 1024 bytes are all zeros.\r\n\r\nWhen both of these are true, the archive is assumed to be finalized. This creates at least one unhandled corner case that I'm aware of - if the archive is not finalized, but the last file in the archive contains at least 1024 zero bytes at the end, the algorithm will treat it as if it's finalized. This will lead to data corruption while appending new files to an existing tar, as those last 1024 bytes will be overwritten. \r\n\r\nSuch a case seemed so unlikely to me that I decided not to change the algorithm, but if someone would like to fix it, one of the solutions that came to my mind is to:\r\n* get the size of the last file;\r\n* check if there's another 1024 bytes after the file's content;\r\n* check if those 1024 bytes are all zeros.\r\n\r\nThis solution would be much more robust, but also more time complex, especially when dealing with archives that contain a lot of files, as it requires finding the last file in the archive.\r\n\r\n## Credits\r\ntarchivist is based on rxi's [microtar](https://github.com/rxi/microtar).\r\n\r\n## License\r\nThis library is free software; you can redistribute it and/or modify it under the terms of the MIT license. See [LICENSE](https://github.com/Lefucjusz/tarchivist/blob/main/LICENSE) for details.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flefucjusz%2Ftarchivist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flefucjusz%2Ftarchivist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flefucjusz%2Ftarchivist/lists"}