mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Remove tix-object-insert.
This commit is contained in:
parent
99d1c61b24
commit
8d5a78d823
2 changed files with 1 additions and 432 deletions
|
@ -18,21 +18,18 @@ tix-collection \
|
|||
tix-execdiff \
|
||||
tix-execpatch \
|
||||
tix-install \
|
||||
tix-object-insert \
|
||||
tix-rmpatch \
|
||||
|
||||
PROGRAMS:=\
|
||||
$(BINARIES) \
|
||||
tix-eradicate-libtool-la \
|
||||
|
||||
LIBS:=-lnettle
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
%: %.cpp util.h
|
||||
$(CXX) -std=gnu++11 $(CPPFLAGS) $(CXXFLAGS) $< -o $@ $(LIBS)
|
||||
$(CXX) -std=gnu++11 $(CPPFLAGS) $(CXXFLAGS) $< -o $@
|
||||
|
||||
$(DESTDIR)$(BINDIR):
|
||||
mkdir -p $@
|
||||
|
|
|
@ -1,428 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of Tix.
|
||||
|
||||
Tix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Tix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Tix. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
tix-object-insert.cpp
|
||||
Inserts files into a tix object database.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nettle/sha.h>
|
||||
|
||||
int create_and_open_directory_at(int dirfd, const char* path, mode_t mode)
|
||||
{
|
||||
|
||||
int ret = openat(dirfd, path, O_RDONLY | O_DIRECTORY);
|
||||
if ( ret < 0 && errno == EEXIST )
|
||||
{
|
||||
if ( mkdirat(dirfd, path, mode) != 0 )
|
||||
return -1;
|
||||
return openat(dirfd, path, O_RDONLY | O_DIRECTORY);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct options
|
||||
{
|
||||
bool hash;
|
||||
bool quiet;
|
||||
bool link;
|
||||
bool symlink;
|
||||
};
|
||||
|
||||
bool insert_object(struct options* opts,
|
||||
const char* file_path,
|
||||
const char* tmp,
|
||||
int database_fd, const char* database_path,
|
||||
const char* digest,
|
||||
int dir_fd, const char* dir_name)
|
||||
{
|
||||
const char* entry_name = digest + 2;
|
||||
if ( linkat(database_fd, tmp, dir_fd, entry_name, 0) &&
|
||||
errno != EEXIST )
|
||||
{
|
||||
error(0, errno, "`%s/%s' -> `%s/%s/%s'", database_path, dir_name,
|
||||
database_path, dir_name, entry_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( opts->hash )
|
||||
printf("%s\n", digest);
|
||||
else if ( !opts->quiet )
|
||||
printf("`%s' -> `%s/%s/%s'\n", file_path,
|
||||
database_path, dir_name, entry_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool insert_object(struct options* opts,
|
||||
const char* file_path,
|
||||
const char* tmp,
|
||||
int database_fd, const char* database_path,
|
||||
const char* digest)
|
||||
{
|
||||
char dir_name[3] = { digest[0], digest[1], '\0' };
|
||||
int dir_fd = create_and_open_directory_at(database_fd, dir_name, 0777);
|
||||
if ( dir_fd < 0 )
|
||||
{
|
||||
error(0, errno, "`%s/%s'", database_path, dir_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = insert_object(opts, file_path, tmp, database_fd, database_path, digest, dir_fd, dir_name);
|
||||
|
||||
close(dir_fd);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool copy_and_hash(FILE* fpin, const char* file_path,
|
||||
FILE* fpout, const char* tmp,
|
||||
int /*database_fd*/, const char* database_path,
|
||||
char* digest)
|
||||
{
|
||||
struct sha256_ctx shactx;
|
||||
sha256_init(&shactx);
|
||||
|
||||
uint8_t buffer[SHA256_DATA_SIZE];
|
||||
while ( size_t num_bytes = fread(buffer, 1, sizeof(buffer), fpin) )
|
||||
{
|
||||
assert(num_bytes <= UINT_MAX);
|
||||
sha256_update(&shactx, num_bytes, buffer);
|
||||
if ( fwrite(buffer, 1, num_bytes, fpout) != num_bytes )
|
||||
{
|
||||
error(0, errno, "`%s/%s'", database_path, tmp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ferror(fpin) )
|
||||
{
|
||||
error(0, errno, "`%s'", file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( fflush(fpout) != 0 )
|
||||
{
|
||||
error(0, errno, "`%s/%s'", database_path, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t binary_digest[SHA256_DIGEST_SIZE];
|
||||
sha256_digest(&shactx, sizeof(binary_digest), binary_digest);
|
||||
|
||||
for ( size_t n = 0; n < SHA256_DIGEST_SIZE; n++ )
|
||||
snprintf(digest + 2 * n, 3, "%02x", binary_digest[n]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool insert_object(struct options* opts,
|
||||
FILE* fpin, const char* file_path,
|
||||
FILE* fpout, const char* tmp,
|
||||
int database_fd, const char* database_path)
|
||||
{
|
||||
char digest[2 * SHA256_DIGEST_SIZE + 1];
|
||||
|
||||
if ( !copy_and_hash(fpin, file_path, fpout, tmp, database_fd,
|
||||
database_path, digest) )
|
||||
return false;
|
||||
|
||||
return insert_object(opts, file_path, tmp, database_fd, database_path, digest);
|
||||
}
|
||||
|
||||
// TODO: Preferably use O_TMPFILE to avoid naming the file until we have made a
|
||||
// copy whose hash we know.
|
||||
bool insert_object(struct options* opts,
|
||||
FILE* fpin, const char* file_path,
|
||||
int database_fd, const char* database_path)
|
||||
{
|
||||
char tmp[8 + 1 + sizeof(pid_t) * 3 + 1];
|
||||
snprintf(tmp, sizeof(tmp), "incoming.%ji", (intmax_t) getpid());
|
||||
int tmp_fd = openat(database_fd, tmp, O_CREAT | O_WRONLY | O_EXCL, 0444);
|
||||
if ( tmp_fd < 0 )
|
||||
{
|
||||
error(0, errno, "`%s/%s'", database_path, tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* fpout = fdopen(tmp_fd, "w");
|
||||
if ( !fpout )
|
||||
{
|
||||
error(0, errno, "fdopen(%i)", tmp_fd);
|
||||
close(tmp_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = insert_object(opts, fpin, file_path, fpout, tmp, database_fd, database_path);
|
||||
|
||||
fclose(fpout);
|
||||
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool insert_object(struct options* opts,
|
||||
const char* file_path,
|
||||
int database_fd, const char* database_path)
|
||||
{
|
||||
if ( !strcmp(file_path, "-") )
|
||||
return insert_object(opts, stdin, file_path, database_fd, database_path);
|
||||
|
||||
FILE* fpin = fopen(file_path, "r");
|
||||
if ( !fpin )
|
||||
error(1, errno, "`%s'", file_path);
|
||||
|
||||
bool success = insert_object(opts, fpin, file_path, database_fd, database_path);
|
||||
|
||||
fclose(fpin);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void help(FILE* fp, const char* argv0)
|
||||
{
|
||||
fprintf(fp, "Usage: %s [OPTION]... [-l | -s] --database DATABASE FILE...\n", argv0);
|
||||
fprintf(fp, "Inserts files into a tix object database.\n");
|
||||
}
|
||||
|
||||
void usage(FILE* fp, const char* argv0)
|
||||
{
|
||||
help(fp, argv0);
|
||||
}
|
||||
|
||||
void version(FILE* fp, const char* argv0)
|
||||
{
|
||||
help(fp, argv0);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* argv0 = argv[0];
|
||||
const char* database_path = NULL;
|
||||
bool hash = false;
|
||||
bool quiet = false;
|
||||
bool do_link = false;
|
||||
bool do_symlink = false;
|
||||
|
||||
for ( int i = 0; i < argc; i++ )
|
||||
{
|
||||
const char* arg = argv[i];
|
||||
if ( arg[0] != '-' )
|
||||
continue;
|
||||
argv[i] = NULL;
|
||||
if ( !strcmp(arg, "--") )
|
||||
break;
|
||||
if ( arg[1] != '-' )
|
||||
{
|
||||
while ( char c = *++arg ) switch ( c )
|
||||
{
|
||||
case 'h': hash = true;
|
||||
case 'l': do_link = true;
|
||||
case 'q': quiet = true;
|
||||
case 's': do_link = true;
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
|
||||
usage(stderr, argv0);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if ( !strcmp(arg, "--help") )
|
||||
help(stdout, argv0), exit(0);
|
||||
else if ( !strcmp(arg, "--usage") )
|
||||
usage(stdout, argv0), exit(0);
|
||||
else if ( !strcmp(arg, "--version") )
|
||||
version(stdout, argv0), exit(0);
|
||||
else if ( !strcmp(arg, "--database") )
|
||||
{
|
||||
if ( i + 1 == argc )
|
||||
error(1, 0, "`--database' expected argument");
|
||||
database_path = argv[++i], argv[i] = NULL;
|
||||
}
|
||||
else if ( !strcmp(arg, "--hash") )
|
||||
hash = true;
|
||||
else if ( !strcmp(arg, "--link") )
|
||||
do_link = true;
|
||||
else if ( !strcmp(arg, "--quiet") )
|
||||
quiet = true;
|
||||
else if ( !strcmp(arg, "--symlink") )
|
||||
do_symlink = true;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: unknown option: `%s'\n", argv0, arg);
|
||||
usage(stderr, argv0);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ( argc == 1 )
|
||||
usage(stdout, argv0), exit(0);
|
||||
|
||||
if ( do_link && do_symlink )
|
||||
{
|
||||
error(0, 0, "error: the -l and -s options are mutually exclusive");
|
||||
usage(stdout, argv0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( !database_path )
|
||||
{
|
||||
error(1, 0, "no `--database' option given, don't know what database");
|
||||
usage(stdout, argv0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int database_fd = open(database_path, O_RDONLY | O_DIRECTORY);
|
||||
if ( database_fd < 0 )
|
||||
error(1, errno, "`%s'", database_path);
|
||||
|
||||
for ( int i = 1; i < argc; i++ )
|
||||
{
|
||||
const char* file_path = argv[i];
|
||||
if ( !file_path )
|
||||
continue;
|
||||
|
||||
FILE* fpin = fopen(file_path, "r");
|
||||
if ( !fpin )
|
||||
error(1, errno, "`%s'", file_path);
|
||||
|
||||
char tmp[8 + 1 + sizeof(pid_t) * 3 + 1];
|
||||
snprintf(tmp, sizeof(tmp), "incoming.%ju", (uintmax_t) getpid());
|
||||
int tmp_fd = openat(database_fd, tmp, O_CREAT | O_WRONLY | O_EXCL, 0444);
|
||||
if ( tmp_fd < 0 )
|
||||
error(1, errno, "`%s/%s'", database_path, tmp);
|
||||
FILE* fpout = fdopen(tmp_fd, "w");
|
||||
|
||||
struct sha256_ctx shactx;
|
||||
sha256_init(&shactx);
|
||||
|
||||
uint8_t buffer[SHA256_DATA_SIZE];
|
||||
while ( size_t num_bytes = fread(buffer, 1, sizeof(buffer), fpin) )
|
||||
{
|
||||
assert(num_bytes <= UINT_MAX);
|
||||
sha256_update(&shactx, num_bytes, buffer);
|
||||
if ( fwrite(buffer, 1, num_bytes, fpout) != num_bytes )
|
||||
{
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
error(1, errno, "`%s/%s'", database_path, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ferror(fpin) )
|
||||
{
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
error(1, errno, "`%s'", file_path);
|
||||
}
|
||||
fclose(fpin);
|
||||
|
||||
if ( fflush(fpout) != 0 )
|
||||
{
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
error(1, errno, "`%s/%s'", database_path, tmp);
|
||||
}
|
||||
|
||||
fclose(fpout);
|
||||
|
||||
uint8_t binary_digest[SHA256_DIGEST_SIZE];
|
||||
sha256_digest(&shactx, sizeof(binary_digest), binary_digest);
|
||||
char digest[2 * SHA256_DIGEST_SIZE + 1];
|
||||
for ( size_t n = 0; n < SHA256_DIGEST_SIZE; n++ )
|
||||
snprintf(digest + 2 * n, 3, "%02x", binary_digest[n]);
|
||||
|
||||
char dir_name[3] = { digest[0], digest[1], '\0' };
|
||||
if ( mkdirat(database_fd, dir_name, 0777) != 0 &&
|
||||
errno != EEXIST )
|
||||
{
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
error(1, errno, "`%s/%s'", database_path, dir_name);
|
||||
}
|
||||
|
||||
int dir_fd = openat(database_fd, dir_name, O_RDONLY | O_DIRECTORY);
|
||||
if ( dir_fd < 0 )
|
||||
{
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
error(1, errno, "`%s/%s'", database_path, dir_name);
|
||||
}
|
||||
|
||||
const char* entry_name = digest + 2;
|
||||
if ( linkat(database_fd, tmp, dir_fd, entry_name, 0) &&
|
||||
errno != EEXIST )
|
||||
{
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
error(1, errno, "`%s/%s' -> `%s/%s/%s'", database_path, dir_name,
|
||||
database_path, dir_name, entry_name);
|
||||
}
|
||||
|
||||
close(dir_fd);
|
||||
|
||||
unlinkat(database_fd, tmp, 0);
|
||||
|
||||
if ( hash )
|
||||
printf("%s\n", digest);
|
||||
else if ( !quiet )
|
||||
printf("`%s' -> `%s/%s/%s'\n", file_path,
|
||||
database_path, dir_name, entry_name);
|
||||
|
||||
if ( do_link || do_symlink )
|
||||
{
|
||||
if ( unlink(file_path) < 0 )
|
||||
error(1, errno, "cannot unlink: `%s'", file_path);
|
||||
|
||||
size_t link_dest_length = strlen(database_path) + 1 + strlen(dir_name) + strlen(entry_name);
|
||||
char* link_dest = (char*) malloc(sizeof(char) * (link_dest_length + 1));
|
||||
|
||||
stpcpy(stpcpy(stpcpy(stpcpy(stpcpy(link_dest, database_path), "/"), dir_name), "/"), entry_name);
|
||||
|
||||
if ( do_symlink )
|
||||
{
|
||||
if ( symlink(link_dest, file_path) < 0 )
|
||||
error(1, errno, "cannot symlink `%s' to `%s'", file_path,
|
||||
link_dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( link(link_dest, file_path) < 0 )
|
||||
error(1, errno, "cannot link `%s' to `%s'", file_path,
|
||||
link_dest);
|
||||
}
|
||||
|
||||
free(link_dest);
|
||||
}
|
||||
}
|
||||
|
||||
close(database_fd);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue