X-Git-Url: https://git.sven.stormbind.net/?p=sven%2Fexfatprogs.git;a=blobdiff_plain;f=lib%2Flibexfat.c;fp=lib%2Flibexfat.c;h=d7b8344f760e6dd7ca1815029d5f14ef9ae424f2;hp=4fd4ac6686e37dcf8a8aa0b6e5b2e1b7ee8019a5;hb=fa2bead8d3f2203fb7b22d801443109a52808490;hpb=0a7a8b470671035ad0c2d8dc0d7714d06921273d diff --git a/lib/libexfat.c b/lib/libexfat.c index 4fd4ac6..d7b8344 100644 --- a/lib/libexfat.c +++ b/lib/libexfat.c @@ -412,6 +412,7 @@ int exfat_read_volume_label(struct exfat *exfat) __le16 disk_label[VOLUME_LABEL_MAX_LEN]; struct exfat_lookup_filter filter = { .in.type = EXFAT_VOLUME, + .in.dentry_count = 0, .in.filter = NULL, }; @@ -453,6 +454,7 @@ int exfat_set_volume_label(struct exfat *exfat, char *label_input) struct exfat_lookup_filter filter = { .in.type = EXFAT_VOLUME, + .in.dentry_count = 1, .in.filter = NULL, }; @@ -492,6 +494,167 @@ int exfat_set_volume_label(struct exfat *exfat, char *label_input) return err; } +static inline void print_guid(const char *msg, const __u8 *guid) +{ + exfat_info("%s: %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + msg, + guid[0], guid[1], guid[2], guid[3], + guid[4], guid[5], guid[5], guid[7], + guid[8], guid[9], guid[10], guid[11], + guid[12], guid[13], guid[14], guid[15]); +} + +static int set_guid(__u8 *guid, const char *input) +{ + int i, j, zero_len = 0; + int len = strlen(input); + + if (len != VOLUME_GUID_LEN * 2 && len != VOLUME_GUID_LEN * 2 + 4) { + exfat_err("invalid format for volume guid\n"); + return -EINVAL; + } + + for (i = 0, j = 0; i < len; i++) { + unsigned char ch = input[i]; + + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if (ch >= 'a' && ch <= 'f') + ch -= 'a' - 0xA; + else if (ch >= 'A' && ch <= 'F') + ch -= 'A' - 0xA; + else if (ch == '-' && len == VOLUME_GUID_LEN * 2 + 4 && + (i == 8 || i == 13 || i == 18 || i == 23)) + continue; + else { + exfat_err("invalid character '%c' for volume GUID\n", ch); + return -EINVAL; + } + + if (j & 1) + guid[j >> 1] |= ch; + else + guid[j >> 1] = ch << 4; + + j++; + + if (ch == 0) + zero_len++; + } + + if (zero_len == VOLUME_GUID_LEN * 2) { + exfat_err("%s is invalid for volume GUID\n", input); + return -EINVAL; + } + + return 0; +} + +int exfat_read_volume_guid(struct exfat *exfat) +{ + int err; + uint16_t checksum = 0; + struct exfat_dentry *dentry; + struct exfat_lookup_filter filter = { + .in.type = EXFAT_GUID, + .in.dentry_count = 1, + .in.filter = NULL, + }; + + err = exfat_lookup_dentry_set(exfat, exfat->root, &filter); + if (err) + return err; + + dentry = filter.out.dentry_set; + exfat_calc_dentry_checksum(dentry, &checksum, true); + + if (cpu_to_le16(checksum) == dentry->dentry.guid.checksum) + print_guid("GUID", dentry->dentry.guid.guid); + else + exfat_info("GUID is corrupted, please delete it or set a new one\n"); + + free(dentry); + + return err; +} + +int __exfat_set_volume_guid(struct exfat_dentry *dentry, const char *guid) +{ + int err; + uint16_t checksum = 0; + + memset(dentry, 0, sizeof(*dentry)); + dentry->type = EXFAT_GUID; + + err = set_guid(dentry->dentry.guid.guid, guid); + if (err) + return err; + + exfat_calc_dentry_checksum(dentry, &checksum, true); + dentry->dentry.guid.checksum = cpu_to_le16(checksum); + + return 0; +} + +/* + * Create/Update/Delete GUID dentry in root directory + * + * create/update GUID if @guid is not NULL. + * delete GUID if @guid is NULL. + */ +int exfat_set_volume_guid(struct exfat *exfat, const char *guid) +{ + struct exfat_dentry *dentry; + struct exfat_dentry_loc loc; + int err; + + struct exfat_lookup_filter filter = { + .in.type = EXFAT_GUID, + .in.dentry_count = 1, + .in.filter = NULL, + }; + + err = exfat_lookup_dentry_set(exfat, exfat->root, &filter); + if (!err) { + /* GUID entry is found */ + dentry = filter.out.dentry_set; + } else { + /* no GUID to delete */ + if (guid == NULL) + return 0; + + dentry = calloc(1, sizeof(*dentry)); + if (!dentry) + return -ENOMEM; + } + + if (guid) { + /* Set GUID */ + err = __exfat_set_volume_guid(dentry, guid); + if (err) + goto out; + } else { + /* Delete GUID */ + dentry->type &= ~EXFAT_INVAL; + } + + loc.parent = exfat->root; + loc.file_offset = filter.out.file_offset; + loc.dev_offset = filter.out.dev_offset; + err = exfat_add_dentry_set(exfat, &loc, dentry, 1, false); + if (!err) { + if (guid) + print_guid("new GUID", dentry->dentry.guid.guid); + else + exfat_info("GUID is deleted\n"); + } + +out: + free(dentry); + + return err; +} + int exfat_read_sector(struct exfat_blk_dev *bd, void *buf, unsigned int sec_off) { int ret;