diff --git a/01-git/check-mssilenin/README.md b/01-git/check-mssilenin/README.md new file mode 100644 index 00000000..71dc00cf --- /dev/null +++ b/01-git/check-mssilenin/README.md @@ -0,0 +1,21 @@ +# Сборка +``` +zig build-exe check.zig +``` + +# Запуск +``` +./check +``` + +# Пример вывода корректного дерева (dir ./correct) +``` +checking commit hash; commit_hash=eac6b33b5eeae8d1e88a3343fc00e8e9c3a5ab120198aecd5c39665852dd0016 +checking commit hash; commit_hash=ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 +checking commit hash; commit_hash=ea57e88f130debd48188990f1175c6cd891ef11017c1145fbf07f39ec2503aa8 +checking commit hash; commit_hash=86012759befd37636df5cc94ad673676a336616acd8b6156ae1bfdaf77465924 +All is correct! +``` + +# Некорректное дерево +Может вернуться либо ошибка IncorrectHash, в случае неверного хеша в названии файла или директории, либо FileNotFound в случае несуществующего файла или директории diff --git a/01-git/check-mssilenin/check.zig b/01-git/check-mssilenin/check.zig new file mode 100644 index 00000000..14ee34e2 --- /dev/null +++ b/01-git/check-mssilenin/check.zig @@ -0,0 +1,159 @@ +const std = @import("std"); +const sha2 = std.crypto.hash.sha2; +const Allocator = std.mem.Allocator; + +const GB = 1 << 30; +const HASH_SIZE = 32; +const HEX_SIZE = 64; + +const ErrorIncorrectTree = error{ + IncorrectHash, + FileNotFound, +}; + +fn checkBufHash(buf: []const u8, expected: []const u8) !void { + var hash: [HASH_SIZE]u8 = undefined; + sha2.Sha256.hash(buf, &hash, .{}); + + var slice_hash = std.mem.bytesAsSlice(u8, &hash); + + var hex_bytes: [HEX_SIZE]u8 = undefined; + _ = try std.fmt.bufPrint(&hex_bytes, "{}", .{std.fmt.fmtSliceHexLower(slice_hash)}); + var hex_slice = std.mem.bytesAsSlice(u8, &hex_bytes); + + for (hex_slice, expected) |value1, value2| { + if (value1 != value2) { + return ErrorIncorrectTree.IncorrectHash; + } + } +} + +fn readCommit(allocator: Allocator, name: []const u8) ![]const u8 { + var file = try std.fs.cwd().openFile(name, .{}); + const file_buffer = try file.readToEndAlloc(allocator, GB); + file.close(); + + return file_buffer; +} + +fn readAndCheckCommit(allocator: Allocator, hash: []const u8) ![]const u8 { + // read current commit + std.debug.print("checking commit hash; commit_hash={s}\n", .{hash}); + var file_buffer = try readCommit(allocator, hash); + + // check if hash of commit != name + try checkBufHash(file_buffer, hash); + + return file_buffer; +} + +fn findDir(allocator: Allocator, root_dir: []const u8, commit_hash: []const u8) ![]const u8 { + var current_commit_hash = try allocator.alloc(u8, commit_hash.len); + std.mem.copy(u8, current_commit_hash, commit_hash); + + if (std.mem.eql(u8, root_dir, ".")) { + return current_commit_hash; + } + + var dirs_it = std.mem.split(u8, root_dir, "/"); + + while (dirs_it.next()) |dir| { + var file_buffer = try readCommit(allocator, current_commit_hash); + defer allocator.free(file_buffer); + + // split commit by '\n' + var lines = std.mem.split(u8, file_buffer, "\n"); + while (lines.next()) |line| { + // skip empty line + if (line.len == 0) { + continue; + } + + // split line by '/\t' + var it = std.mem.split(u8, line, "/\t"); + var commit_dir = it.next(); + + // file -> skip + if (it.peek() == null) { + continue; + } + + // find commit_dir == dir + if (std.mem.eql(u8, dir, commit_dir.?)) { + allocator.free(current_commit_hash); + + var hash = it.peek().?; + current_commit_hash = try allocator.alloc(u8, hash.len); + std.mem.copy(u8, current_commit_hash, hash); + break; + } + } + } + + if (std.mem.eql(u8, current_commit_hash, commit_hash)) { + std.debug.print("dir={s} is not found\n", .{root_dir}); + + return ErrorIncorrectTree.FileNotFound; + } + + std.debug.print("found dir={s}\n", .{current_commit_hash}); + + return current_commit_hash; +} + +fn checkFile(allocator: Allocator, name: []const u8) !void { + var file_buffer = try readAndCheckCommit(allocator, name); + defer allocator.free(file_buffer); +} + +fn checkDir(allocator: Allocator, name: []const u8) !void { + var file_buffer = try readAndCheckCommit(allocator, name); + defer allocator.free(file_buffer); + + // split commit by '\n' + var lines = std.mem.split(u8, file_buffer, "\n"); + while (lines.next()) |line| { + // skip empty line + if (line.len == 0) { + continue; + } + + // split line by '/\t' + var it = std.mem.split(u8, line, "/\t"); + _ = it.next(); // skip name of dir + + // file (len(it) == 1) + if (it.peek() == null) { + var file_it = std.mem.split(u8, line, ":\t"); + _ = file_it.next(); // skip name of file + + try checkFile(allocator, file_it.next().?); + + continue; + } + + // dir + try checkDir(allocator, it.next().?); + } +} + +pub fn main() !void { + const allocator = std.heap.page_allocator; + + var args = try std.process.argsAlloc(allocator); + defer std.process.argsFree(allocator, args); + if (args.len != 3) { + std.debug.print("Usage: ./check \n", .{}); + return; + } + + const dir = args[1]; + const start_hash = args[2]; + + var hash = try findDir(allocator, dir, start_hash); + defer allocator.free(hash); + + try checkDir(allocator, hash); + + std.debug.print("All is correct!\n", .{}); +} diff --git a/01-git/check-mssilenin/correct/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf b/01-git/check-mssilenin/correct/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf new file mode 100644 index 00000000..63db2144 --- /dev/null +++ b/01-git/check-mssilenin/correct/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf @@ -0,0 +1,2 @@ +file.txt: ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 +subdir/ ea57e88f130debd48188990f1175c6cd891ef11017c1145fbf07f39ec2503aa8 \ No newline at end of file diff --git a/01-git/check-mssilenin/correct/86012759befd37636df5cc94ad673676a336616acd8b6156ae1bfdaf77465924 b/01-git/check-mssilenin/correct/86012759befd37636df5cc94ad673676a336616acd8b6156ae1bfdaf77465924 new file mode 100644 index 00000000..2c315a99 --- /dev/null +++ b/01-git/check-mssilenin/correct/86012759befd37636df5cc94ad673676a336616acd8b6156ae1bfdaf77465924 @@ -0,0 +1 @@ +smth \ No newline at end of file diff --git a/01-git/check-mssilenin/correct/ea57e88f130debd48188990f1175c6cd891ef11017c1145fbf07f39ec2503aa8 b/01-git/check-mssilenin/correct/ea57e88f130debd48188990f1175c6cd891ef11017c1145fbf07f39ec2503aa8 new file mode 100644 index 00000000..f465bd25 --- /dev/null +++ b/01-git/check-mssilenin/correct/ea57e88f130debd48188990f1175c6cd891ef11017c1145fbf07f39ec2503aa8 @@ -0,0 +1 @@ +subdir_file.txt: 86012759befd37636df5cc94ad673676a336616acd8b6156ae1bfdaf77465924 \ No newline at end of file diff --git a/01-git/check-mssilenin/correct/eac6b33b5eeae8d1e88a3343fc00e8e9c3a5ab120198aecd5c39665852dd0016 b/01-git/check-mssilenin/correct/eac6b33b5eeae8d1e88a3343fc00e8e9c3a5ab120198aecd5c39665852dd0016 new file mode 100644 index 00000000..9bcaaa1e --- /dev/null +++ b/01-git/check-mssilenin/correct/eac6b33b5eeae8d1e88a3343fc00e8e9c3a5ab120198aecd5c39665852dd0016 @@ -0,0 +1,2 @@ +file.txt: ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 +subdir/ ea57e88f130debd48188990f1175c6cd891ef11017c1145fbf07f39ec2503aa8 diff --git a/01-git/check-mssilenin/correct/ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 b/01-git/check-mssilenin/correct/ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 new file mode 100644 index 00000000..f8147e4d --- /dev/null +++ b/01-git/check-mssilenin/correct/ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 @@ -0,0 +1 @@ +so so \ No newline at end of file diff --git a/01-git/check-mssilenin/incorrect_dir_hash/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf b/01-git/check-mssilenin/incorrect_dir_hash/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf new file mode 100644 index 00000000..ad8f9e06 --- /dev/null +++ b/01-git/check-mssilenin/incorrect_dir_hash/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf @@ -0,0 +1 @@ +file.txt: ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 \ No newline at end of file diff --git a/01-git/check-mssilenin/incorrect_dir_hash/ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 b/01-git/check-mssilenin/incorrect_dir_hash/ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 new file mode 100644 index 00000000..f8147e4d --- /dev/null +++ b/01-git/check-mssilenin/incorrect_dir_hash/ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 @@ -0,0 +1 @@ +so so \ No newline at end of file diff --git a/01-git/check-mssilenin/incorrect_file_hash/dbdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 b/01-git/check-mssilenin/incorrect_file_hash/dbdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 new file mode 100644 index 00000000..f8147e4d --- /dev/null +++ b/01-git/check-mssilenin/incorrect_file_hash/dbdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 @@ -0,0 +1 @@ +so so \ No newline at end of file diff --git a/01-git/check-mssilenin/incorrect_file_hash/e67e94fb8713fe93b620dd2f2054fcc11d70d820fedd6a3125247fb93dee8f3f b/01-git/check-mssilenin/incorrect_file_hash/e67e94fb8713fe93b620dd2f2054fcc11d70d820fedd6a3125247fb93dee8f3f new file mode 100644 index 00000000..242b32a2 --- /dev/null +++ b/01-git/check-mssilenin/incorrect_file_hash/e67e94fb8713fe93b620dd2f2054fcc11d70d820fedd6a3125247fb93dee8f3f @@ -0,0 +1 @@ +file.txt: dbdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 \ No newline at end of file diff --git a/01-git/check-mssilenin/unknown_file/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf b/01-git/check-mssilenin/unknown_file/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf new file mode 100644 index 00000000..63db2144 --- /dev/null +++ b/01-git/check-mssilenin/unknown_file/61ec58ece347e6ac22f5227c642410bfad51e33bd2ca57e1f9d5b85502fa4ddf @@ -0,0 +1,2 @@ +file.txt: ebdd7b80aa4838dc4585af7f7d47b643024be479822f6c59b7c6313ce8322173 +subdir/ ea57e88f130debd48188990f1175c6cd891ef11017c1145fbf07f39ec2503aa8 \ No newline at end of file