util.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
  177. {
  178. ssize_t buf_len;
  179. dbg("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len);
  180. /* check if requested area fits in superblock buffer */
  181. if (off + len <= SB_BUFFER_SIZE) {
  182. if (id->sbbuf == NULL) {
  183. id->sbbuf = xmalloc(SB_BUFFER_SIZE);
  184. }
  185. /* check if we need to read */
  186. if ((off + len) > id->sbbuf_len) {
  187. dbg("read sbbuf len:0x%llx", (unsigned long long) (off + len));
  188. xlseek(id->fd, 0, SEEK_SET);
  189. buf_len = full_read(id->fd, id->sbbuf, off + len);
  190. if (buf_len < 0) {
  191. dbg("read failed (%s)", strerror(errno));
  192. return NULL;
  193. }
  194. dbg("got 0x%zx (%zi) bytes", buf_len, buf_len);
  195. id->sbbuf_len = buf_len;
  196. if ((uint64_t)buf_len < off + len) {
  197. dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len);
  198. return NULL;
  199. }
  200. }
  201. return &(id->sbbuf[off]);
  202. }
  203. if (len > SEEK_BUFFER_SIZE) {
  204. dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
  205. return NULL;
  206. }
  207. /* get seek buffer */
  208. if (id->seekbuf == NULL) {
  209. id->seekbuf = xmalloc(SEEK_BUFFER_SIZE);
  210. }
  211. /* check if we need to read */
  212. if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
  213. dbg("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len);
  214. xlseek(id->fd, off, SEEK_SET);
  215. buf_len = full_read(id->fd, id->seekbuf, len);
  216. if (buf_len < 0) {
  217. dbg("read failed (%s)", strerror(errno));
  218. return NULL;
  219. }
  220. dbg("got 0x%zx (%zi) bytes", buf_len, buf_len);
  221. id->seekbuf_off = off;
  222. id->seekbuf_len = buf_len;
  223. if ((size_t)buf_len < len) {
  224. dbg("requested 0x%zx bytes, got only 0x%zx bytes", len, buf_len);
  225. return NULL;
  226. }
  227. }
  228. return &(id->seekbuf[off - id->seekbuf_off]);
  229. }
  230. void volume_id_free_buffer(struct volume_id *id)
  231. {
  232. free(id->sbbuf);
  233. id->sbbuf = NULL;
  234. id->sbbuf_len = 0;
  235. free(id->seekbuf);
  236. id->seekbuf = NULL;
  237. id->seekbuf_len = 0;
  238. }