1: 盘符 和 卷标的区别

之前被这个概念迷惑了很久, 走了不少弯路。


盘符 - window下的概念。 例如 C: 盘 D: 盘, C和D 这是就是盘符。 Linux下无对应的概念。


卷标 - 例如 C 盘如果命名为系统, D盘命名为电影, 系统和电影 这才是卷标。 Linux下也有这东西, 这个属于文件系统的部分。



2: Android 下如何获取卷标


StorageVolume.java 中的 public String getUserLabel() 获取。



3: Android现在支持的情况


如果这么简单获取那就方便了, 首先  StorageVolume.java 这个类是不公开的, 获取方法可以通过反射。


其次  public String getUserLabel()  这个方法, 底层和上层根本就没调通(Android4.4的原生代码部分, 我看是调试通过了)。




1: Vold 接收到 U 盘插入事件。


执行 Volume.cpp 的 int Volume::mountVol() 方法 这里调用  int Volume::extractMetadata(const char* devicePath)方法 。




/*
 * Use blkid to extract UUID and label from device, since it handles many
 * obscure edge cases around partition types and formats. Always broadcasts
 * updated metadata values.
 */
int Volume::extractMetadata(const char* devicePath) {
    int res = 0;

    std::string cmd;
    cmd = BLKID_PATH;
    cmd += " -c /dev/null ";
    cmd += devicePath;

    FILE* fp = popen(cmd.c_str(), "r");
    if (!fp) {
        SLOGI("Failed to run %s: %s", cmd.c_str(), strerror(errno));
        res = -1;
        goto done;
    }

    char line[1024];
    char value[128];
    if (fgets(line, sizeof(line), fp) != NULL) {
        SLOGI("blkid identified as %s", line);

        char* start = strstr(line, "UUID=");
        if (start != NULL && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
            setUuid(value);
        } else {
            setUuid(NULL);
        }

        start = strstr(line, "LABEL=");
        if (start != NULL && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
            setUserLabel(value);
        } else {
            setUserLabel(NULL);
        }
    } else {
        SLOGI("blkid failed to identify %s", devicePath);
        res = -1;
    }

    pclose(fp);

done:
    if (res == -1) {
        setUuid(NULL);
        setUserLabel(NULL);
    }
    return res;
}






通过代码就可以 U盘的基本信息 UUID 和 LABEL 都是通过 blkid 获取的。




4: blkid 分析


通过 static void print_tags(blkid_dev dev, char *show[], int numtag, int output) 把相关的信息进行输出。



5: blkid如何支持中文


这个就涉及到字符集相关的问题了, 说一个迷惑了我很久的字符集问题。


字符集包括unicode, gbk 以及gb2312等等,  但是utf-8, 这个东西不是字符集。这个是字符编码。


举个例子就明白啥叫字符编码了。


C中的字符串(char*)问题, 我们认为一个字符串的长度是, 读取到ASCII 0(‘/0’)的位置位置。


假设字符串 "A" 的GBK和UTF8编码都是 0x410 x00, 为啥后面多了个0x00, 这个就是字符串的结束位置。


字符A的 Unicode编码是 0x00 0x41, 如果用char*传递unicode字符串, 不知道字符串大小, 肯定是有问题的。 读到第一个0x00就结束了。


还不明白可以百度了。



对于vfat,fat32格式的U盘, 在windows下命名中文, 保存的字符编码是CP936(跟GBK差不多), 但是对于ntfs格式的u盘, 保存的方式是unicode。




这里涉及到android(linux)的编码问题, linux的默认编码是utf-8. 所以如果要正常显示, 需要在linux中合适的位置坐转码。



思路:


(只涉及中文, 韩文日文不考虑)在blkid这里把, 把编码直接从gbk转到utf8. (/external/e2fsprogs/misc/blkid.c)


特殊的ntfs获取卷标的地方, 为了上层的gbk编码兼容, 可以直接把unicode先转成gbk。(/external/e2fsprogs/lib/blkid/probe.c)



至于编码之间的转换可以参考网上的代码, 也可以使用开源的库iconv. 个人认为可以代码量比较小, 可以考虑网上的参考代码。