/* TODO: how should we properly handle compute_hash() failures? */ int compute_hash(struct file *file, char *filename) { int ret; char key[SWUPD_HASH_LEN]; size_t key_len; unsigned char *blob; FILE *fl; if (file->is_deleted) { hash_set_zeros(file->hash); return 0; } hash_set_zeros(key); if (file->is_link) { char link[PATH_MAXLEN]; memset(link, 0, PATH_MAXLEN); ret = readlink(filename, link, PATH_MAXLEN - 1); if (ret >= 0) { hmac_compute_key(filename, &file->stat, key, &key_len, file->use_xattrs); hmac_sha256_for_string(file->hash, (const unsigned char *)key, key_len, link); return 0; } else { return -1; } } if (file->is_dir) { hmac_compute_key(filename, &file->stat, key, &key_len, file->use_xattrs); hmac_sha256_for_string(file->hash, (const unsigned char *)key, key_len, SWUPD_HASH_DIRNAME); //Make independent of dirname return 0; } /* if we get here, this is a regular file */ fl = fopen(filename, "r"); if (!fl) { return -1; } blob = mmap(NULL, file->stat.st_size, PROT_READ, MAP_PRIVATE, fileno(fl), 0); if (blob == MAP_FAILED && file->stat.st_size != 0) { abort(); } hmac_compute_key(filename, &file->stat, key, &key_len, file->use_xattrs); hmac_sha256_for_data(file->hash, (const unsigned char *)key, key_len, blob, file->stat.st_size); munmap(blob, file->stat.st_size); fclose(fl); return 0; }
/* this function MUST be kept in sync with the server * return is NULL if there was an error. If the file does not exist, * a "0000000..." hash is returned as is our convention in the manifest * for deleted files */ char *compute_hash(struct file *file, char *filename) { struct stat stat; int ret; unsigned char *blob; char *key = NULL; size_t key_len; FILE *fl; struct update_stat tfstat; char *hash = NULL; memset(&stat, 0, sizeof(stat)); memset(&tfstat, 0, sizeof(tfstat)); ret = lstat(filename, &stat); if (ret < 0) { if (errno == ENOENT) { LOG_DEBUG(NULL, "File does not exist, mark as deleted", class_file_misc, "%s", filename); file->is_deleted = 1; hash = strdup("0000000000000000000000000000000000000000000000000000000000000000"); if (!hash) abort(); return hash; } LOG_ERROR(NULL, "stat error ", class_file_io, "\\*filename=\"%s\",strerror=\"%s\"*\\", filename, strerror(errno)); return NULL; } tfstat.st_mode = stat.st_mode; tfstat.st_uid = stat.st_uid; tfstat.st_gid = stat.st_gid; tfstat.st_rdev = stat.st_rdev; tfstat.st_size = stat.st_size; /* just server does this: file->size = stat.st_size; */ if ((file->is_link) || (S_ISLNK(stat.st_mode))) { char link[PATH_MAXLEN]; memset(link, 0, PATH_MAXLEN); file->is_file = 0; file->is_dir = 0; file->is_link = 1; ret = readlink(filename, link, PATH_MAXLEN - 1); memset(&tfstat.st_mode, 0, sizeof(tfstat.st_mode)); if (ret >= 0) { hmac_compute_key(filename, &tfstat, &key, &key_len, file->use_xattrs); hash = hmac_sha256_for_string( (const unsigned char *)key, key_len, link); if (!hash) abort(); free(key); return hash; } else { LOG_ERROR(NULL, "readlink error ", class_file_io, "\\*ret=\"%i\",errno=\"%i\",strerror=\"%s\"*\\", ret, errno, strerror(errno)); return NULL; } } if ((file->is_dir) || (S_ISDIR(stat.st_mode))) { file->is_file = 0; file->is_dir = 1; file->is_link = 0; tfstat.st_size = 0; hmac_compute_key(filename, &tfstat, &key, &key_len, file->use_xattrs); hash = hmac_sha256_for_string( (const unsigned char *)key, key_len, file->filename); //file->filename not filename if (!hash) abort(); free(key); return hash; } /* if we get here, this is a regular file */ file->is_file = 1; file->is_dir = 0; file->is_link = 0; fl = fopen(filename, "r"); if (!fl) { LOG_ERROR(NULL, "file open error ", class_file_io, "\\*filename=\"%s\",strerror=\"%s\"*\\", filename, strerror(errno)); return NULL; } blob = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fileno(fl), 0); if (blob == MAP_FAILED && stat.st_size != 0) abort(); hmac_compute_key(filename, &tfstat, &key, &key_len, file->use_xattrs); hash = hmac_sha256_for_data( (const unsigned char *)key, key_len, blob, stat.st_size); munmap(blob, stat.st_size); fclose(fl); if (!hash) abort(); free(key); return hash; }