PageRenderTime 80ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/ntfs-3g/ntfsprogs/ntfslabel.c

https://gitlab.com/envieidoc/advancedtomato2
C | 463 lines | 343 code | 38 blank | 82 comment | 72 complexity | ecbde77ec10e003f89716cc3222d4e56 MD5 | raw file
  1. /**
  2. * ntfslabel - Part of the Linux-NTFS project.
  3. *
  4. * Copyright (c) 2002 Matthew J. Fanto
  5. * Copyright (c) 2002-2005 Anton Altaparmakov
  6. * Copyright (c) 2002-2003 Richard Russon
  7. * Copyright (c) 2012-2014 Jean-Pierre Andre
  8. *
  9. * This utility will display/change the label on an NTFS partition.
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program (in the main directory of the Linux-NTFS
  23. * distribution in the file COPYING); if not, write to the Free Software
  24. * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25. */
  26. #include "config.h"
  27. #ifdef HAVE_STDLIB_H
  28. #include <stdlib.h>
  29. #endif
  30. #ifdef HAVE_STDIO_H
  31. #include <stdio.h>
  32. #endif
  33. #ifdef HAVE_STRING_H
  34. #include <string.h>
  35. #endif
  36. #ifdef HAVE_ERRNO_H
  37. #include <errno.h>
  38. #endif
  39. #ifdef HAVE_LOCALE_H
  40. #include <locale.h>
  41. #endif
  42. #ifdef HAVE_GETOPT_H
  43. #include <getopt.h>
  44. #endif
  45. #ifdef HAVE_UNISTD_H
  46. #include <unistd.h>
  47. #endif
  48. #include "debug.h"
  49. #include "mft.h"
  50. #include "utils.h"
  51. /* #include "version.h" */
  52. #include "logging.h"
  53. #include "misc.h"
  54. static const char *EXEC_NAME = "ntfslabel";
  55. static struct options {
  56. char *device; /* Device/File to work with */
  57. char *label; /* Set the label to this */
  58. int quiet; /* Less output */
  59. int verbose; /* Extra output */
  60. int force; /* Override common sense */
  61. int new_serial; /* Change the serial number */
  62. unsigned long long serial; /* Forced serial number value */
  63. int noaction; /* Do not write to disk */
  64. } opts;
  65. /**
  66. * version - Print version information about the program
  67. *
  68. * Print a copyright statement and a brief description of the program.
  69. *
  70. * Return: none
  71. */
  72. static void version(void)
  73. {
  74. ntfs_log_info("\n%s v%s (libntfs-3g) - Display, or set, the label for an "
  75. "NTFS Volume.\n\n", EXEC_NAME, VERSION);
  76. ntfs_log_info("Copyright (c)\n");
  77. ntfs_log_info(" 2002 Matthew J. Fanto\n");
  78. ntfs_log_info(" 2002-2005 Anton Altaparmakov\n");
  79. ntfs_log_info(" 2002-2003 Richard Russon\n");
  80. ntfs_log_info(" 2012-2014 Jean-Pierre Andre\n");
  81. ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
  82. }
  83. /**
  84. * usage - Print a list of the parameters to the program
  85. *
  86. * Print a list of the parameters and options for the program.
  87. *
  88. * Return: none
  89. */
  90. static void usage(void)
  91. {
  92. ntfs_log_info("\nUsage: %s [options] device [label]\n"
  93. " -n, --no-action Do not write to disk\n"
  94. " -f, --force Use less caution\n"
  95. " --new-serial Set a new serial number\n"
  96. " --new-half-serial Set a partial new serial number\n"
  97. " -q, --quiet Less output\n"
  98. " -v, --verbose More output\n"
  99. " -V, --version Display version information\n"
  100. " -h, --help Display this help\n\n",
  101. EXEC_NAME);
  102. ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
  103. }
  104. /**
  105. * parse_options - Read and validate the programs command line
  106. *
  107. * Read the command line, verify the syntax and parse the options.
  108. * This function is very long, but quite simple.
  109. *
  110. * Return: 1 Success
  111. * 0 Error, one or more problems
  112. */
  113. static int parse_options(int argc, char *argv[])
  114. {
  115. static const char *sopt = "-fh?IinqvV";
  116. static const struct option lopt[] = {
  117. { "force", no_argument, NULL, 'f' },
  118. { "help", no_argument, NULL, 'h' },
  119. { "new-serial", optional_argument, NULL, 'I' },
  120. { "new-half-serial", optional_argument, NULL, 'i' },
  121. { "no-action", no_argument, NULL, 'n' },
  122. { "quiet", no_argument, NULL, 'q' },
  123. { "verbose", no_argument, NULL, 'v' },
  124. { "version", no_argument, NULL, 'V' },
  125. { NULL, 0, NULL, 0 },
  126. };
  127. int c = -1;
  128. int err = 0;
  129. int ver = 0;
  130. int help = 0;
  131. int levels = 0;
  132. char *endserial;
  133. opterr = 0; /* We'll handle the errors, thank you. */
  134. while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
  135. switch (c) {
  136. case 1: /* A non-option argument */
  137. if (!err && !opts.device)
  138. opts.device = argv[optind-1];
  139. else if (!err && !opts.label)
  140. opts.label = argv[optind-1];
  141. else
  142. err++;
  143. break;
  144. case 'f':
  145. opts.force++;
  146. break;
  147. case 'h':
  148. help++;
  149. break;
  150. case 'I' : /* not proposed as a short option letter */
  151. if (optarg) {
  152. opts.serial = strtoull(optarg, &endserial, 16);
  153. if (*endserial)
  154. ntfs_log_error("Bad hexadecimal serial number.\n");
  155. }
  156. opts.new_serial |= 2;
  157. break;
  158. case 'i' : /* not proposed as a short option letter */
  159. if (optarg) {
  160. opts.serial = strtoull(optarg, &endserial, 16)
  161. << 32;
  162. if (*endserial)
  163. ntfs_log_error("Bad hexadecimal serial number.\n");
  164. }
  165. opts.new_serial |= 1;
  166. break;
  167. case 'n':
  168. opts.noaction++;
  169. break;
  170. case 'q':
  171. opts.quiet++;
  172. ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
  173. break;
  174. case 'v':
  175. opts.verbose++;
  176. ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
  177. break;
  178. case 'V':
  179. ver++;
  180. break;
  181. case '?':
  182. if (strncmp (argv[optind-1], "--log-", 6) == 0) {
  183. if (!ntfs_log_parse_option (argv[optind-1]))
  184. err++;
  185. break;
  186. }
  187. /* fall through */
  188. default:
  189. ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
  190. err++;
  191. break;
  192. }
  193. }
  194. /* Make sure we're in sync with the log levels */
  195. levels = ntfs_log_get_levels();
  196. if (levels & NTFS_LOG_LEVEL_VERBOSE)
  197. opts.verbose++;
  198. if (!(levels & NTFS_LOG_LEVEL_QUIET))
  199. opts.quiet++;
  200. if (help || ver) {
  201. opts.quiet = 0;
  202. } else {
  203. if (opts.device == NULL) {
  204. if (argc > 1)
  205. ntfs_log_error("You must specify a device.\n");
  206. err++;
  207. }
  208. if (opts.quiet && opts.verbose) {
  209. ntfs_log_error("You may not use --quiet and --verbose at "
  210. "the same time.\n");
  211. err++;
  212. }
  213. }
  214. if (ver)
  215. version();
  216. if (help || err)
  217. usage();
  218. /* tri-state 0 : done, 1 : error, -1 : proceed */
  219. return (err ? 1 : (help || ver ? 0 : -1));
  220. }
  221. static int change_serial(ntfs_volume *vol, u64 sector, le64 serial_number,
  222. NTFS_BOOT_SECTOR *bs, NTFS_BOOT_SECTOR *oldbs)
  223. {
  224. int res;
  225. le64 mask;
  226. BOOL same;
  227. res = -1;
  228. if ((ntfs_pread(vol->dev, sector << vol->sector_size_bits,
  229. vol->sector_size, bs) == vol->sector_size)) {
  230. same = TRUE;
  231. if (!sector)
  232. /* save the real bootsector */
  233. memcpy(oldbs, bs, vol->sector_size);
  234. else
  235. /* backup bootsector must be similar */
  236. same = !memcmp(oldbs, bs, vol->sector_size);
  237. if (same) {
  238. if (opts.new_serial & 2)
  239. bs->volume_serial_number = serial_number;
  240. else {
  241. mask = const_cpu_to_le64(~0x0ffffffffULL);
  242. bs->volume_serial_number
  243. = (serial_number & mask)
  244. | (bs->volume_serial_number & ~mask);
  245. }
  246. if (opts.noaction
  247. || (ntfs_pwrite(vol->dev,
  248. sector << vol->sector_size_bits,
  249. vol->sector_size, bs) == vol->sector_size)) {
  250. res = 0;
  251. }
  252. } else {
  253. ntfs_log_info("* Warning : the backup boot sector"
  254. " does not match (leaving unchanged)\n");
  255. res = 0;
  256. }
  257. }
  258. return (res);
  259. }
  260. static int set_new_serial(ntfs_volume *vol)
  261. {
  262. NTFS_BOOT_SECTOR *bs; /* full boot sectors */
  263. NTFS_BOOT_SECTOR *oldbs; /* full original boot sector */
  264. le64 serial_number;
  265. u64 number_of_sectors;
  266. u64 sn;
  267. int res;
  268. res = -1;
  269. bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
  270. oldbs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
  271. if (bs && oldbs) {
  272. if (opts.serial)
  273. serial_number = cpu_to_le64(opts.serial);
  274. else {
  275. /* different values for parallel processes */
  276. srandom(time((time_t*)NULL) ^ (getpid() << 16));
  277. sn = ((u64)random() << 32)
  278. | ((u64)random() & 0xffffffff);
  279. serial_number = cpu_to_le64(sn);
  280. }
  281. if (!change_serial(vol, 0, serial_number, bs, oldbs)) {
  282. number_of_sectors = le64_to_cpu(bs->number_of_sectors);
  283. if (!change_serial(vol, number_of_sectors,
  284. serial_number, bs, oldbs)) {
  285. ntfs_log_info("New serial number : %016llx\n",
  286. (long long)le64_to_cpu(
  287. bs->volume_serial_number));
  288. res = 0;
  289. }
  290. }
  291. free(bs);
  292. free(oldbs);
  293. }
  294. if (res)
  295. ntfs_log_info("Error setting a new serial number\n");
  296. return (res);
  297. }
  298. static int print_serial(ntfs_volume *vol)
  299. {
  300. NTFS_BOOT_SECTOR *bs; /* full boot sectors */
  301. int res;
  302. res = -1;
  303. bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
  304. if (bs
  305. && (ntfs_pread(vol->dev, 0,
  306. vol->sector_size, bs) == vol->sector_size)) {
  307. ntfs_log_info("Serial number : %016llx\n",
  308. (long long)le64_to_cpu(bs->volume_serial_number));
  309. res = 0;
  310. free(bs);
  311. }
  312. if (res)
  313. ntfs_log_info("Error getting the serial number\n");
  314. return (res);
  315. }
  316. /**
  317. * print_label - display the current label of a mounted ntfs partition.
  318. * @dev: device to read the label from
  319. * @mnt_flags: mount flags of the device or 0 if not mounted
  320. * @mnt_point: mount point of the device or NULL
  321. *
  322. * Print the label of the device @dev.
  323. */
  324. static int print_label(ntfs_volume *vol, unsigned long mnt_flags)
  325. {
  326. int result = 0;
  327. //XXX significant?
  328. if ((mnt_flags & (NTFS_MF_MOUNTED | NTFS_MF_READONLY)) ==
  329. NTFS_MF_MOUNTED) {
  330. ntfs_log_error("%s is mounted read-write, results may be "
  331. "unreliable.\n", opts.device);
  332. result = 1;
  333. }
  334. if (opts.verbose)
  335. ntfs_log_info("Volume label : %s\n", vol->vol_name);
  336. else
  337. ntfs_log_info("%s\n", vol->vol_name);
  338. return result;
  339. }
  340. /**
  341. * change_label - change the current label on a device
  342. * @dev: device to change the label on
  343. * @mnt_flags: mount flags of the device or 0 if not mounted
  344. * @mnt_point: mount point of the device or NULL
  345. * @label: the new label
  346. *
  347. * Change the label on the device @dev to @label.
  348. */
  349. static int change_label(ntfs_volume *vol, char *label)
  350. {
  351. ntfschar *new_label = NULL;
  352. int label_len;
  353. int result = 0;
  354. label_len = ntfs_mbstoucs(label, &new_label);
  355. if (label_len == -1) {
  356. ntfs_log_perror("Unable to convert label string to Unicode");
  357. return 1;
  358. }
  359. else if (label_len*sizeof(ntfschar) > 0x100) {
  360. ntfs_log_warning("New label is too long. Maximum %u characters "
  361. "allowed. Truncating %u excess characters.\n",
  362. (unsigned)(0x100 / sizeof(ntfschar)),
  363. (unsigned)(label_len -
  364. (0x100 / sizeof(ntfschar))));
  365. label_len = 0x100 / sizeof(ntfschar);
  366. label[label_len] = const_cpu_to_le16(0);
  367. }
  368. if(!opts.noaction)
  369. result = ntfs_volume_rename(vol, new_label, label_len) ? 1 : 0;
  370. free(new_label);
  371. return result;
  372. }
  373. /**
  374. * main - Begin here
  375. *
  376. * Start from here.
  377. *
  378. * Return: 0 Success, the program worked
  379. * 1 Error, something went wrong
  380. */
  381. int main(int argc, char **argv)
  382. {
  383. unsigned long mnt_flags = 0;
  384. int result = 0;
  385. ntfs_volume *vol;
  386. ntfs_log_set_handler(ntfs_log_handler_outerr);
  387. result = parse_options(argc, argv);
  388. if (result >= 0)
  389. return (result);
  390. result = 0;
  391. utils_set_locale();
  392. if ((opts.label || opts.new_serial)
  393. && !opts.noaction
  394. && !opts.force
  395. && !ntfs_check_if_mounted(opts.device, &mnt_flags)
  396. && (mnt_flags & NTFS_MF_MOUNTED)) {
  397. ntfs_log_error("Cannot make changes to a mounted device\n");
  398. result = 1;
  399. goto abort;
  400. }
  401. if (!opts.label && !opts.new_serial)
  402. opts.noaction++;
  403. vol = utils_mount_volume(opts.device,
  404. (opts.noaction ? NTFS_MNT_RDONLY : 0) |
  405. (opts.force ? NTFS_MNT_RECOVER : 0));
  406. if (!vol)
  407. return 1;
  408. if (opts.new_serial) {
  409. result = set_new_serial(vol);
  410. if (result)
  411. goto unmount;
  412. } else {
  413. if (opts.verbose)
  414. result = print_serial(vol);
  415. }
  416. if (opts.label)
  417. result = change_label(vol, opts.label);
  418. else
  419. result = print_label(vol, mnt_flags);
  420. unmount :
  421. ntfs_umount(vol, FALSE);
  422. abort :
  423. /* "result" may be a negative reply of a library function */
  424. return (result ? 1 : 0);
  425. }