diff --git a/09-xattr/checksum.c b/09-xattr/checksum.c
index 2c14d4e..8ced836 100644
--- a/09-xattr/checksum.c
+++ b/09-xattr/checksum.c
@@ -17,10 +17,26 @@
// length in *len and an open file descriptor in *fd.
// On error, the function should return the null pointer;
char * map_file(char *fn, ssize_t *len, int *fd) {
- // FIXME: Map file to memory
- // FIXME: Set *len = ...
- // FIXME: Set *fd = ...
- return NULL;
+ // We use stat to check if the file exists and to determine which
+ struct stat s;
+ int rc = stat(fn, &s);
+ if (rc < 0) return NULL;
+
+ // Open the file read only.
+ int _fd = open(fn, O_RDONLY);
+ if (! _fd) return NULL;
+
+ // Map the file as shared and read only somewhere to memory
+ char *map = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, _fd, 0);
+ // mmap returns a special pointer (MAP_FAILED) to indicate that
+ // the operation did not succeed.
+ if (map == MAP_FAILED)
+ return NULL;
+
+ // We return three value to our caller
+ *len = s.st_size;
+ *fd = _fd;
+ return map;
}
// A (very) simple checksum function that calculates and additive checksum over a memory range.
@@ -62,11 +78,52 @@ int main(int argc, char *argv[]) {
} else {
fprintf(stderr, "usage: %s [-r] <FILE>\n", argv[0]);
}
- // Avoid compiler warnings
- (void) fn; (void) reset_checksum; (void) xattr;
- // FIXME: map the file
- // FIXME: reset the checksum if requested
- // FIXME: calculate the checksum
- // FIXME: get the old checksum and perform checking
- // FIXME: set the new checksum
+ // We map the file to memory, get the length and an open file
+ // descriptor. Later on we will only use the file-descriptor based
+ // variants of {set,remove,get}xattr as that avoids the TOCTOU
+ // (time-of-check, time-of-update) problem.
+ ssize_t len;
+ int fd;
+ char *data = map_file(fn, &len, &fd);
+ if (!data) die("map_file");
+
+ // If we are instructed to remove the checksum, we use
+ // fremovexattr to delete it. For the error checking, we allow it
+ // that the checksum was not set beforehand.
+ if (reset_checksum) {
+ int rc = fremovexattr(fd, xattr);
+ if (rc < 0 && errno != ENODATA) {
+ die("fremovexattr");
+ }
+ return 0;
+ }
+
+ // We are sure that the file is mapped, so we can calcucate the
+ // checksum over the memory mapped file.
+ uint64_t checksum = calc_checksum(data, len);
+ printf("current_checksum: %lx\n", checksum);
+
+ // The final return code
+ int ret = 0;
+
+ // We get the old checksum from the file. Please note that we
+ // store the checksum as the raw 8 bytes of the uint64_t
+ uint64_t old_checksum;
+ if (fgetxattr(fd, xattr, &old_checksum, sizeof(old_checksum)) != sizeof(old_checksum)) {
+ printf("old_checksum: NULL\n");
+ } else {
+ printf("previous_checksum: %lx\n", old_checksum);
+
+ // On checksum mismatch, we will return an error.
+ if (checksum != old_checksum) {
+ fprintf(stderr, "checksum mismatch!");
+ ret = -1;
+ }
+ }
+
+ // In the end, we override the current checksum.
+ if (fsetxattr(fd, xattr, &checksum, sizeof(checksum), 0) != 0) {
+ die("fsetxattr");
+ }
+ return ret;
}