util.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * volume_id - reads filesystem label and uuid
  3. *
  4. * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "volume_id_internal.h"
  21. void volume_id_set_unicode16(char *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count)
  22. {
  23. unsigned i, j;
  24. unsigned c;
  25. j = 0;
  26. for (i = 0; i + 2 <= count; i += 2) {
  27. if (endianess == LE)
  28. c = (buf[i+1] << 8) | buf[i];
  29. else
  30. c = (buf[i] << 8) | buf[i+1];
  31. if (c == 0)
  32. break;
  33. if (j+1 >= len)
  34. break;
  35. if (c < 0x80) {
  36. /* 0xxxxxxx */
  37. } else {
  38. uint8_t topbits = 0xc0;
  39. if (j+2 >= len)
  40. break;
  41. if (c < 0x800) {
  42. /* 110yyyxx 10xxxxxx */
  43. } else {
  44. if (j+3 >= len)
  45. break;
  46. /* 1110yyyy 10yyyyxx 10xxxxxx */
  47. str[j++] = (uint8_t) (0xe0 | (c >> 12));
  48. topbits = 0x80;
  49. }
  50. str[j++] = (uint8_t) (topbits | ((c >> 6) & 0x3f));
  51. c = 0x80 | (c & 0x3f);
  52. }
  53. str[j++] = (uint8_t) c;
  54. }
  55. str[j] = '\0';
  56. }
  57. #ifdef UNUSED
  58. static const char *usage_to_string(enum volume_id_usage usage_id)
  59. {
  60. switch (usage_id) {
  61. case VOLUME_ID_FILESYSTEM:
  62. return "filesystem";
  63. case VOLUME_ID_PARTITIONTABLE:
  64. return "partitiontable";
  65. case VOLUME_ID_OTHER:
  66. return "other";
  67. case VOLUME_ID_RAID:
  68. return "raid";
  69. case VOLUME_ID_DISKLABEL:
  70. return "disklabel";
  71. case VOLUME_ID_CRYPTO:
  72. return "crypto";
  73. case VOLUME_ID_UNPROBED:
  74. return "unprobed";
  75. case VOLUME_ID_UNUSED:
  76. return "unused";
  77. }
  78. return NULL;
  79. }
  80. void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id)
  81. {
  82. part->usage_id = usage_id;
  83. part->usage = usage_to_string(usage_id);
  84. }
  85. void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id)
  86. {
  87. id->usage_id = usage_id;
  88. id->usage = usage_to_string(usage_id);
  89. }
  90. void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count)
  91. {
  92. memcpy(id->label_raw, buf, count);
  93. id->label_raw_len = count;
  94. }
  95. #endif
  96. #ifdef NOT_NEEDED
  97. static size_t strnlen(const char *s, size_t maxlen)
  98. {
  99. size_t i;
  100. if (!maxlen) return 0;
  101. if (!s) return 0;
  102. for (i = 0; *s && i < maxlen; ++s) ++i;
  103. return i;
  104. }
  105. #endif
  106. void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count)
  107. {
  108. unsigned i;
  109. memcpy(id->label, buf, count);
  110. /* remove trailing whitespace */
  111. i = strnlen(id->label, count);
  112. while (i--) {
  113. if (!isspace(id->label[i]))
  114. break;
  115. }
  116. id->label[i+1] = '\0';
  117. }
  118. void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count)
  119. {
  120. volume_id_set_unicode16(id->label, sizeof(id->label), buf, endianess, count);
  121. }
  122. void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format)
  123. {
  124. unsigned i;
  125. unsigned count = (format == UUID_DCE_STRING ? VOLUME_ID_UUID_SIZE : 4 << format);
  126. // memcpy(id->uuid_raw, buf, count);
  127. // id->uuid_raw_len = count;
  128. /* if set, create string in the same format, the native platform uses */
  129. for (i = 0; i < count; i++)
  130. if (buf[i] != 0)
  131. goto set;
  132. return; /* all bytes are zero, leave it empty ("") */
  133. set:
  134. switch (format) {
  135. case UUID_DOS:
  136. sprintf(id->uuid, "%02X%02X-%02X%02X",
  137. buf[3], buf[2], buf[1], buf[0]);
  138. break;
  139. case UUID_NTFS:
  140. sprintf(id->uuid, "%02X%02X%02X%02X%02X%02X%02X%02X",
  141. buf[7], buf[6], buf[5], buf[4],
  142. buf[3], buf[2], buf[1], buf[0]);
  143. break;
  144. case UUID_DCE:
  145. sprintf(id->uuid,
  146. "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  147. buf[0], buf[1], buf[2], buf[3],
  148. buf[4], buf[5],
  149. buf[6], buf[7],
  150. buf[8], buf[9],
  151. buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
  152. break;
  153. case UUID_DCE_STRING:
  154. memcpy(id->uuid, buf, count);
  155. id->uuid[count] = '\0';
  156. break;
  157. }
  158. }
  159. /* Do not use xlseek here. With it, single corrupted filesystem
  160. * may result in attempt to seek past device -> exit.
  161. * It's better to ignore such fs and continue. */
  162. void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
  163. {
  164. uint8_t *dst;
  165. unsigned small_off;
  166. ssize_t read_len;
  167. dbg("get buffer off 0x%llx(%llu), len 0x%zx",
  168. (unsigned long long) off, (unsigned long long) off, len);
  169. /* check if requested area fits in superblock buffer */
  170. if (off + len <= SB_BUFFER_SIZE
  171. /* && off <= SB_BUFFER_SIZE - want this paranoid overflow check? */
  172. ) {
  173. if (id->sbbuf == NULL) {
  174. id->sbbuf = xmalloc(SB_BUFFER_SIZE);
  175. }
  176. small_off = off;
  177. dst = id->sbbuf;
  178. /* check if we need to read */
  179. len += off;
  180. if (len <= id->sbbuf_len)
  181. goto ret; /* we already have it */
  182. dbg("read sbbuf len:0x%x", (unsigned) len);
  183. id->sbbuf_len = len;
  184. off = 0;
  185. goto do_read;
  186. }
  187. if (len > SEEK_BUFFER_SIZE) {
  188. dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
  189. return NULL;
  190. }
  191. dst = id->seekbuf;
  192. /* check if we need to read */
  193. if ((off >= id->seekbuf_off)
  194. && ((off + len) <= (id->seekbuf_off + id->seekbuf_len))
  195. ) {
  196. small_off = off - id->seekbuf_off; /* can't overflow */
  197. goto ret; /* we already have it */
  198. }
  199. id->seekbuf_off = off;
  200. id->seekbuf_len = len;
  201. id->seekbuf = xrealloc(id->seekbuf, len);
  202. small_off = 0;
  203. dst = id->seekbuf;
  204. dbg("read seekbuf off:0x%llx len:0x%zx",
  205. (unsigned long long) off, len);
  206. do_read:
  207. if (lseek(id->fd, off, SEEK_SET) != off) {
  208. dbg("seek(0x%llx) failed", (unsigned long long) off);
  209. goto err;
  210. }
  211. read_len = full_read(id->fd, dst, len);
  212. if (read_len != len) {
  213. dbg("requested 0x%x bytes, got 0x%x bytes",
  214. (unsigned) len, (unsigned) read_len);
  215. err:
  216. /* No filesystem can be this tiny. It's most likely
  217. * non-associated loop device, empty drive and so on.
  218. * Flag it, making it possible to short circuit future
  219. * accesses. Rationale:
  220. * users complained of slow blkid due to empty floppy drives.
  221. */
  222. if (off < 64*1024)
  223. id->error = 1;
  224. /* id->seekbuf_len or id->sbbuf_len is wrong now! Fixing. */
  225. volume_id_free_buffer(id);
  226. return NULL;
  227. }
  228. ret:
  229. return dst + small_off;
  230. }
  231. void volume_id_free_buffer(struct volume_id *id)
  232. {
  233. free(id->sbbuf);
  234. id->sbbuf = NULL;
  235. id->sbbuf_len = 0;
  236. free(id->seekbuf);
  237. id->seekbuf = NULL;
  238. id->seekbuf_len = 0;
  239. id->seekbuf_off = 0; /* paranoia */
  240. }