util.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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. str[j] = '\0';
  33. break;
  34. } else if (c < 0x80) {
  35. if (j+1 >= len)
  36. break;
  37. str[j++] = (uint8_t) c;
  38. } else if (c < 0x800) {
  39. if (j+2 >= len)
  40. break;
  41. str[j++] = (uint8_t) (0xc0 | (c >> 6));
  42. str[j++] = (uint8_t) (0x80 | (c & 0x3f));
  43. } else {
  44. if (j+3 >= len)
  45. break;
  46. str[j++] = (uint8_t) (0xe0 | (c >> 12));
  47. str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
  48. str[j++] = (uint8_t) (0x80 | (c & 0x3f));
  49. }
  50. }
  51. str[j] = '\0';
  52. }
  53. #ifdef UNUSED
  54. static const char *usage_to_string(enum volume_id_usage usage_id)
  55. {
  56. switch (usage_id) {
  57. case VOLUME_ID_FILESYSTEM:
  58. return "filesystem";
  59. case VOLUME_ID_PARTITIONTABLE:
  60. return "partitiontable";
  61. case VOLUME_ID_OTHER:
  62. return "other";
  63. case VOLUME_ID_RAID:
  64. return "raid";
  65. case VOLUME_ID_DISKLABEL:
  66. return "disklabel";
  67. case VOLUME_ID_CRYPTO:
  68. return "crypto";
  69. case VOLUME_ID_UNPROBED:
  70. return "unprobed";
  71. case VOLUME_ID_UNUSED:
  72. return "unused";
  73. }
  74. return NULL;
  75. }
  76. void volume_id_set_usage_part(struct volume_id_partition *part, enum volume_id_usage usage_id)
  77. {
  78. part->usage_id = usage_id;
  79. part->usage = usage_to_string(usage_id);
  80. }
  81. void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id)
  82. {
  83. id->usage_id = usage_id;
  84. id->usage = usage_to_string(usage_id);
  85. }
  86. void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count)
  87. {
  88. memcpy(id->label_raw, buf, count);
  89. id->label_raw_len = count;
  90. }
  91. #endif
  92. #ifdef NOT_NEEDED
  93. static size_t strnlen(const char *s, size_t maxlen)
  94. {
  95. size_t i;
  96. if (!maxlen) return 0;
  97. if (!s) return 0;
  98. for (i = 0; *s && i < maxlen; ++s) ++i;
  99. return i;
  100. }
  101. #endif
  102. void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count)
  103. {
  104. unsigned i;
  105. memcpy(id->label, buf, count);
  106. /* remove trailing whitespace */
  107. i = strnlen(id->label, count);
  108. while (i--) {
  109. if (!isspace(id->label[i]))
  110. break;
  111. }
  112. id->label[i+1] = '\0';
  113. }
  114. void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count)
  115. {
  116. volume_id_set_unicode16(id->label, sizeof(id->label), buf, endianess, count);
  117. }
  118. void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, enum uuid_format format)
  119. {
  120. unsigned i;
  121. unsigned count = 0;
  122. switch (format) {
  123. case UUID_DOS:
  124. count = 4;
  125. break;
  126. case UUID_NTFS:
  127. case UUID_HFS:
  128. count = 8;
  129. break;
  130. case UUID_DCE:
  131. count = 16;
  132. break;
  133. case UUID_DCE_STRING:
  134. /* 36 is ok, id->uuid has one extra byte for NUL */
  135. count = VOLUME_ID_UUID_SIZE;
  136. break;
  137. }
  138. // memcpy(id->uuid_raw, buf, count);
  139. // id->uuid_raw_len = count;
  140. /* if set, create string in the same format, the native platform uses */
  141. for (i = 0; i < count; i++)
  142. if (buf[i] != 0)
  143. goto set;
  144. return; /* all bytes are zero, leave it empty ("") */
  145. set:
  146. switch (format) {
  147. case UUID_DOS:
  148. sprintf(id->uuid, "%02X%02X-%02X%02X",
  149. buf[3], buf[2], buf[1], buf[0]);
  150. break;
  151. case UUID_NTFS:
  152. sprintf(id->uuid, "%02X%02X%02X%02X%02X%02X%02X%02X",
  153. buf[7], buf[6], buf[5], buf[4],
  154. buf[3], buf[2], buf[1], buf[0]);
  155. break;
  156. case UUID_HFS:
  157. sprintf(id->uuid, "%02X%02X%02X%02X%02X%02X%02X%02X",
  158. buf[0], buf[1], buf[2], buf[3],
  159. buf[4], buf[5], buf[6], buf[7]);
  160. break;
  161. case UUID_DCE:
  162. sprintf(id->uuid,
  163. "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  164. buf[0], buf[1], buf[2], buf[3],
  165. buf[4], buf[5],
  166. buf[6], buf[7],
  167. buf[8], buf[9],
  168. buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
  169. break;
  170. case UUID_DCE_STRING:
  171. memcpy(id->uuid, buf, count);
  172. id->uuid[count] = '\0';
  173. break;
  174. }
  175. }
  176. /* Do not use xlseek here. With it, single corrupted filesystem
  177. * may result in attempt to seek past device -> exit.
  178. * It's better to ignore such fs and continue. */
  179. void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
  180. {
  181. uint8_t *dst;
  182. unsigned small_off;
  183. ssize_t read_len;
  184. dbg("get buffer off 0x%llx(%llu), len 0x%zx",
  185. (unsigned long long) off, (unsigned long long) off, len);
  186. /* check if requested area fits in superblock buffer */
  187. if (off + len <= SB_BUFFER_SIZE
  188. /* && off <= SB_BUFFER_SIZE - want this paranoid overflow check? */
  189. ) {
  190. if (id->sbbuf == NULL) {
  191. id->sbbuf = xmalloc(SB_BUFFER_SIZE);
  192. }
  193. small_off = off;
  194. dst = id->sbbuf;
  195. /* check if we need to read */
  196. len += off;
  197. if (len <= id->sbbuf_len)
  198. goto ret; /* we already have it */
  199. dbg("read sbbuf len:0x%x", (unsigned) len);
  200. id->sbbuf_len = len;
  201. off = 0;
  202. goto do_read;
  203. }
  204. if (len > SEEK_BUFFER_SIZE) {
  205. dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
  206. return NULL;
  207. }
  208. dst = id->seekbuf;
  209. /* check if we need to read */
  210. if ((off >= id->seekbuf_off)
  211. && ((off + len) <= (id->seekbuf_off + id->seekbuf_len))
  212. ) {
  213. small_off = off - id->seekbuf_off; /* can't overflow */
  214. goto ret; /* we already have it */
  215. }
  216. id->seekbuf_off = off;
  217. id->seekbuf_len = len;
  218. id->seekbuf = xrealloc(id->seekbuf, len);
  219. small_off = 0;
  220. dst = id->seekbuf;
  221. dbg("read seekbuf off:0x%llx len:0x%zx",
  222. (unsigned long long) off, len);
  223. do_read:
  224. if (lseek(id->fd, off, SEEK_SET) != off) {
  225. dbg("seek(0x%llx) failed", (unsigned long long) off);
  226. goto err;
  227. }
  228. read_len = full_read(id->fd, dst, len);
  229. if (read_len != len) {
  230. dbg("requested 0x%x bytes, got 0x%x bytes",
  231. (unsigned) len, (unsigned) read_len);
  232. err:
  233. /* No filesystem can be this tiny. It's most likely
  234. * non-associated loop device, empty drive and so on.
  235. * Flag it, making it possible to short circuit future
  236. * accesses. Rationale:
  237. * users complained of slow blkid due to empty floppy drives.
  238. */
  239. if (off < 64*1024)
  240. id->error = 1;
  241. /* id->seekbuf_len or id->sbbuf_len is wrong now! Fixing. */
  242. volume_id_free_buffer(id);
  243. return NULL;
  244. }
  245. ret:
  246. return dst + small_off;
  247. }
  248. void volume_id_free_buffer(struct volume_id *id)
  249. {
  250. free(id->sbbuf);
  251. id->sbbuf = NULL;
  252. id->sbbuf_len = 0;
  253. free(id->seekbuf);
  254. id->seekbuf = NULL;
  255. id->seekbuf_len = 0;
  256. id->seekbuf_off = 0; /* paranoia */
  257. }