"Fossies" - the Fresh Open Source Software Archive

Member "ntfs-3g_ntfsprogs-2017.3.23/ntfsprogs/ntfslabel.c" (23 Mar 2017, 11961 Bytes) of package /linux/misc/ntfs-3g_ntfsprogs-2017.3.23.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ntfslabel.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3g_ntfsprogs-2016.2.22_vs_3g_ntfsprogs-2017.3.23.

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