├── .gitignore ├── COPYING ├── Makefile.am ├── README ├── autogen.sh ├── configure.ac ├── include ├── atomicio.h ├── libvhd-journal.h ├── libvhd.h ├── list.h ├── lvm-util.h ├── relative-path.h ├── vhd-util.h ├── vhd-uuid.h └── vhd.h ├── lib ├── libvhd.c ├── relative-path.c └── vhd-util-uuid.c └── tools ├── common ├── atomicio.c └── libvhd-journal.c ├── vhd-update └── vhd-update.c └── vhd-util ├── lvm-util.c ├── vhd-util-check.c ├── vhd-util-coalesce.c ├── vhd-util-create.c ├── vhd-util-fill.c ├── vhd-util-modify.c ├── vhd-util-query.c ├── vhd-util-read.c ├── vhd-util-repair.c ├── vhd-util-resize.c ├── vhd-util-revert.c ├── vhd-util-scan.c ├── vhd-util-set-field.c ├── vhd-util-snapshot.c └── vhd-util.c /.gitignore: -------------------------------------------------------------------------------- 1 | .libs 2 | .deps 3 | *.o 4 | *.la 5 | *.lo 6 | config 7 | config.log 8 | config.status 9 | configure 10 | aclocal.m4 11 | autom4te.cache 12 | Makefile 13 | Makefile.in 14 | libtool 15 | m4 16 | vhd-util 17 | vhd-update 18 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | ============ 3 | 4 | Below is the wording from the COPYING file found in the xen source 5 | code tree. 6 | 7 | ============ 8 | 9 | 10 | GNU General Public License 11 | -------------------------- 12 | 13 | Most files in this repository are licensed under the terms of the GNU 14 | General Public License (GPL), a copy of which is attached at the end 15 | of this notice. Note that the only valid version of the GPL as far as 16 | the files in this repository are concerned is _this_ particular 17 | version of the license (i.e., *only* v2, not v2.2 or v3.x or 18 | whatever), unless explicitly otherwise stated. 19 | 20 | Some code fragments in the hypervisor and associated subsystems 21 | include the 2- or 3-clause BSD license stanzas (also known as Modified 22 | BSD licenses). When these code sections are compiled as part of a 23 | GPLv2-licensed program, such as Xen, the result is licensed under 24 | GPLv2. See the FSF's definition of GPL compatibility: 25 | http://www.gnu.org/licenses/gpl-faq.html#WhatDoesCompatMean 26 | And how this applies to a range of open source licenses: 27 | http://www.gnu.org/licenses/license-list.html 28 | 29 | Licensing Exceptions (the relaxed BSD-style license) 30 | ---------------------------------------------------- 31 | 32 | For the convenience of users and those who are porting OSes to run as 33 | Xen guests, certain files in this repository are not subject to the 34 | GPL when distributed separately or included in software packages 35 | outside this repository. Instead we specify a much more relaxed 36 | BSD-style license. Affected files include the Xen interface headers 37 | (xen/include/public/COPYING), MiniOS (extras/mini-os) and various 38 | drivers, support functions and header files within Xen-aware Linux 39 | source trees. In all such cases, license terms are stated at the top 40 | of the file or in a COPYING file in the same directory. Note that 41 | _any_ file that is modified and then distributed within a Linux kernel 42 | is still subject to the GNU GPL. 43 | 44 | -- Keir Fraser (on behalf of the Xen team) 45 | 46 | ===================================================================== 47 | 48 | GNU GENERAL PUBLIC LICENSE 49 | Version 2, June 1991 50 | 51 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 52 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 53 | Everyone is permitted to copy and distribute verbatim copies 54 | of this license document, but changing it is not allowed. 55 | 56 | Preamble 57 | 58 | The licenses for most software are designed to take away your 59 | freedom to share and change it. By contrast, the GNU General Public 60 | License is intended to guarantee your freedom to share and change free 61 | software--to make sure the software is free for all its users. This 62 | General Public License applies to most of the Free Software 63 | Foundation's software and to any other program whose authors commit to 64 | using it. (Some other Free Software Foundation software is covered by 65 | the GNU Library General Public License instead.) You can apply it to 66 | your programs, too. 67 | 68 | When we speak of free software, we are referring to freedom, not 69 | price. Our General Public Licenses are designed to make sure that you 70 | have the freedom to distribute copies of free software (and charge for 71 | this service if you wish), that you receive source code or can get it 72 | if you want it, that you can change the software or use pieces of it 73 | in new free programs; and that you know you can do these things. 74 | 75 | To protect your rights, we need to make restrictions that forbid 76 | anyone to deny you these rights or to ask you to surrender the rights. 77 | These restrictions translate to certain responsibilities for you if you 78 | distribute copies of the software, or if you modify it. 79 | 80 | For example, if you distribute copies of such a program, whether 81 | gratis or for a fee, you must give the recipients all the rights that 82 | you have. You must make sure that they, too, receive or can get the 83 | source code. And you must show them these terms so they know their 84 | rights. 85 | 86 | We protect your rights with two steps: (1) copyright the software, and 87 | (2) offer you this license which gives you legal permission to copy, 88 | distribute and/or modify the software. 89 | 90 | Also, for each author's protection and ours, we want to make certain 91 | that everyone understands that there is no warranty for this free 92 | software. If the software is modified by someone else and passed on, we 93 | want its recipients to know that what they have is not the original, so 94 | that any problems introduced by others will not reflect on the original 95 | authors' reputations. 96 | 97 | Finally, any free program is threatened constantly by software 98 | patents. We wish to avoid the danger that redistributors of a free 99 | program will individually obtain patent licenses, in effect making the 100 | program proprietary. To prevent this, we have made it clear that any 101 | patent must be licensed for everyone's free use or not licensed at all. 102 | 103 | The precise terms and conditions for copying, distribution and 104 | modification follow. 105 | 106 | GNU GENERAL PUBLIC LICENSE 107 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 108 | 109 | 0. This License applies to any program or other work which contains 110 | a notice placed by the copyright holder saying it may be distributed 111 | under the terms of this General Public License. The "Program", below, 112 | refers to any such program or work, and a "work based on the Program" 113 | means either the Program or any derivative work under copyright law: 114 | that is to say, a work containing the Program or a portion of it, 115 | either verbatim or with modifications and/or translated into another 116 | language. (Hereinafter, translation is included without limitation in 117 | the term "modification".) Each licensee is addressed as "you". 118 | 119 | Activities other than copying, distribution and modification are not 120 | covered by this License; they are outside its scope. The act of 121 | running the Program is not restricted, and the output from the Program 122 | is covered only if its contents constitute a work based on the 123 | Program (independent of having been made by running the Program). 124 | Whether that is true depends on what the Program does. 125 | 126 | 1. You may copy and distribute verbatim copies of the Program's 127 | source code as you receive it, in any medium, provided that you 128 | conspicuously and appropriately publish on each copy an appropriate 129 | copyright notice and disclaimer of warranty; keep intact all the 130 | notices that refer to this License and to the absence of any warranty; 131 | and give any other recipients of the Program a copy of this License 132 | along with the Program. 133 | 134 | You may charge a fee for the physical act of transferring a copy, and 135 | you may at your option offer warranty protection in exchange for a fee. 136 | 137 | 2. You may modify your copy or copies of the Program or any portion 138 | of it, thus forming a work based on the Program, and copy and 139 | distribute such modifications or work under the terms of Section 1 140 | above, provided that you also meet all of these conditions: 141 | 142 | a) You must cause the modified files to carry prominent notices 143 | stating that you changed the files and the date of any change. 144 | 145 | b) You must cause any work that you distribute or publish, that in 146 | whole or in part contains or is derived from the Program or any 147 | part thereof, to be licensed as a whole at no charge to all third 148 | parties under the terms of this License. 149 | 150 | c) If the modified program normally reads commands interactively 151 | when run, you must cause it, when started running for such 152 | interactive use in the most ordinary way, to print or display an 153 | announcement including an appropriate copyright notice and a 154 | notice that there is no warranty (or else, saying that you provide 155 | a warranty) and that users may redistribute the program under 156 | these conditions, and telling the user how to view a copy of this 157 | License. (Exception: if the Program itself is interactive but 158 | does not normally print such an announcement, your work based on 159 | the Program is not required to print an announcement.) 160 | 161 | These requirements apply to the modified work as a whole. If 162 | identifiable sections of that work are not derived from the Program, 163 | and can be reasonably considered independent and separate works in 164 | themselves, then this License, and its terms, do not apply to those 165 | sections when you distribute them as separate works. But when you 166 | distribute the same sections as part of a whole which is a work based 167 | on the Program, the distribution of the whole must be on the terms of 168 | this License, whose permissions for other licensees extend to the 169 | entire whole, and thus to each and every part regardless of who wrote it. 170 | 171 | Thus, it is not the intent of this section to claim rights or contest 172 | your rights to work written entirely by you; rather, the intent is to 173 | exercise the right to control the distribution of derivative or 174 | collective works based on the Program. 175 | 176 | In addition, mere aggregation of another work not based on the Program 177 | with the Program (or with a work based on the Program) on a volume of 178 | a storage or distribution medium does not bring the other work under 179 | the scope of this License. 180 | 181 | 3. You may copy and distribute the Program (or a work based on it, 182 | under Section 2) in object code or executable form under the terms of 183 | Sections 1 and 2 above provided that you also do one of the following: 184 | 185 | a) Accompany it with the complete corresponding machine-readable 186 | source code, which must be distributed under the terms of Sections 187 | 1 and 2 above on a medium customarily used for software interchange; or, 188 | 189 | b) Accompany it with a written offer, valid for at least three 190 | years, to give any third party, for a charge no more than your 191 | cost of physically performing source distribution, a complete 192 | machine-readable copy of the corresponding source code, to be 193 | distributed under the terms of Sections 1 and 2 above on a medium 194 | customarily used for software interchange; or, 195 | 196 | c) Accompany it with the information you received as to the offer 197 | to distribute corresponding source code. (This alternative is 198 | allowed only for noncommercial distribution and only if you 199 | received the program in object code or executable form with such 200 | an offer, in accord with Subsection b above.) 201 | 202 | The source code for a work means the preferred form of the work for 203 | making modifications to it. For an executable work, complete source 204 | code means all the source code for all modules it contains, plus any 205 | associated interface definition files, plus the scripts used to 206 | control compilation and installation of the executable. However, as a 207 | special exception, the source code distributed need not include 208 | anything that is normally distributed (in either source or binary 209 | form) with the major components (compiler, kernel, and so on) of the 210 | operating system on which the executable runs, unless that component 211 | itself accompanies the executable. 212 | 213 | If distribution of executable or object code is made by offering 214 | access to copy from a designated place, then offering equivalent 215 | access to copy the source code from the same place counts as 216 | distribution of the source code, even though third parties are not 217 | compelled to copy the source along with the object code. 218 | 219 | 4. You may not copy, modify, sublicense, or distribute the Program 220 | except as expressly provided under this License. Any attempt 221 | otherwise to copy, modify, sublicense or distribute the Program is 222 | void, and will automatically terminate your rights under this License. 223 | However, parties who have received copies, or rights, from you under 224 | this License will not have their licenses terminated so long as such 225 | parties remain in full compliance. 226 | 227 | 5. You are not required to accept this License, since you have not 228 | signed it. However, nothing else grants you permission to modify or 229 | distribute the Program or its derivative works. These actions are 230 | prohibited by law if you do not accept this License. Therefore, by 231 | modifying or distributing the Program (or any work based on the 232 | Program), you indicate your acceptance of this License to do so, and 233 | all its terms and conditions for copying, distributing or modifying 234 | the Program or works based on it. 235 | 236 | 6. Each time you redistribute the Program (or any work based on the 237 | Program), the recipient automatically receives a license from the 238 | original licensor to copy, distribute or modify the Program subject to 239 | these terms and conditions. You may not impose any further 240 | restrictions on the recipients' exercise of the rights granted herein. 241 | You are not responsible for enforcing compliance by third parties to 242 | this License. 243 | 244 | 7. If, as a consequence of a court judgment or allegation of patent 245 | infringement or for any other reason (not limited to patent issues), 246 | conditions are imposed on you (whether by court order, agreement or 247 | otherwise) that contradict the conditions of this License, they do not 248 | excuse you from the conditions of this License. If you cannot 249 | distribute so as to satisfy simultaneously your obligations under this 250 | License and any other pertinent obligations, then as a consequence you 251 | may not distribute the Program at all. For example, if a patent 252 | license would not permit royalty-free redistribution of the Program by 253 | all those who receive copies directly or indirectly through you, then 254 | the only way you could satisfy both it and this License would be to 255 | refrain entirely from distribution of the Program. 256 | 257 | If any portion of this section is held invalid or unenforceable under 258 | any particular circumstance, the balance of the section is intended to 259 | apply and the section as a whole is intended to apply in other 260 | circumstances. 261 | 262 | It is not the purpose of this section to induce you to infringe any 263 | patents or other property right claims or to contest validity of any 264 | such claims; this section has the sole purpose of protecting the 265 | integrity of the free software distribution system, which is 266 | implemented by public license practices. Many people have made 267 | generous contributions to the wide range of software distributed 268 | through that system in reliance on consistent application of that 269 | system; it is up to the author/donor to decide if he or she is willing 270 | to distribute software through any other system and a licensee cannot 271 | impose that choice. 272 | 273 | This section is intended to make thoroughly clear what is believed to 274 | be a consequence of the rest of this License. 275 | 276 | 8. If the distribution and/or use of the Program is restricted in 277 | certain countries either by patents or by copyrighted interfaces, the 278 | original copyright holder who places the Program under this License 279 | may add an explicit geographical distribution limitation excluding 280 | those countries, so that distribution is permitted only in or among 281 | countries not thus excluded. In such case, this License incorporates 282 | the limitation as if written in the body of this License. 283 | 284 | 9. The Free Software Foundation may publish revised and/or new versions 285 | of the General Public License from time to time. Such new versions will 286 | be similar in spirit to the present version, but may differ in detail to 287 | address new problems or concerns. 288 | 289 | Each version is given a distinguishing version number. If the Program 290 | specifies a version number of this License which applies to it and "any 291 | later version", you have the option of following the terms and conditions 292 | either of that version or of any later version published by the Free 293 | Software Foundation. If the Program does not specify a version number of 294 | this License, you may choose any version ever published by the Free Software 295 | Foundation. 296 | 297 | 10. If you wish to incorporate parts of the Program into other free 298 | programs whose distribution conditions are different, write to the author 299 | to ask for permission. For software which is copyrighted by the Free 300 | Software Foundation, write to the Free Software Foundation; we sometimes 301 | make exceptions for this. Our decision will be guided by the two goals 302 | of preserving the free status of all derivatives of our free software and 303 | of promoting the sharing and reuse of software generally. 304 | 305 | NO WARRANTY 306 | 307 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 308 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 309 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 310 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 311 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 312 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 313 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 314 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 315 | REPAIR OR CORRECTION. 316 | 317 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 318 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 319 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 320 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 321 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 322 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 323 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 324 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 325 | POSSIBILITY OF SUCH DAMAGES. 326 | 327 | END OF TERMS AND CONDITIONS 328 | 329 | How to Apply These Terms to Your New Programs 330 | 331 | If you develop a new program, and you want it to be of the greatest 332 | possible use to the public, the best way to achieve this is to make it 333 | free software which everyone can redistribute and change under these terms. 334 | 335 | To do so, attach the following notices to the program. It is safest 336 | to attach them to the start of each source file to most effectively 337 | convey the exclusion of warranty; and each file should have at least 338 | the "copyright" line and a pointer to where the full notice is found. 339 | 340 | 341 | Copyright (C) 342 | 343 | This program is free software; you can redistribute it and/or modify 344 | it under the terms of the GNU General Public License as published by 345 | the Free Software Foundation; either version 2 of the License, or 346 | (at your option) any later version. 347 | 348 | This program is distributed in the hope that it will be useful, 349 | but WITHOUT ANY WARRANTY; without even the implied warranty of 350 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 351 | GNU General Public License for more details. 352 | 353 | You should have received a copy of the GNU General Public License 354 | along with this program; if not, write to the Free Software 355 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 356 | 357 | 358 | Also add information on how to contact you by electronic and paper mail. 359 | 360 | If the program is interactive, make it output a short notice like this 361 | when it starts in an interactive mode: 362 | 363 | Gnomovision version 69, Copyright (C) year name of author 364 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 365 | This is free software, and you are welcome to redistribute it 366 | under certain conditions; type `show c' for details. 367 | 368 | The hypothetical commands `show w' and `show c' should show the appropriate 369 | parts of the General Public License. Of course, the commands you use may 370 | be called something other than `show w' and `show c'; they could even be 371 | mouse-clicks or menu items--whatever suits your program. 372 | 373 | You should also get your employer (if you work as a programmer) or your 374 | school, if any, to sign a "copyright disclaimer" for the program, if 375 | necessary. Here is a sample; alter the names: 376 | 377 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 378 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 379 | 380 | , 1 April 1989 381 | Ty Coon, President of Vice 382 | 383 | This General Public License does not permit incorporating your program into 384 | proprietary programs. If your program is a subroutine library, you may 385 | consider it more useful to permit linking proprietary applications with the 386 | library. If this is what you want to do, use the GNU Library General 387 | Public License instead of this License. 388 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | ACLOCAL_AMFLAGS = -I m4 3 | LDADD = libvhd.la 4 | AM_CFLAGS = -Iinclude -D_GNU_SOURCE 5 | 6 | bin_PROGRAMS = 7 | check_PROGRAMS = 8 | noinst_PROGRAMS = 9 | lib_LTLIBRARIES = 10 | noinst_LTLIBRARIES = 11 | nobase_include_HEADERS = 12 | include_HEADERS = 13 | noinst_HEADERS = 14 | CLEANFILES = 15 | EXTRA_DIST = autogen.sh \ 16 | include/atomicio.h \ 17 | include/libvhd-journal.h \ 18 | include/list.h \ 19 | include/lvm-util.h \ 20 | include/relative-path.h \ 21 | include/vhd.h \ 22 | include/vhd-util.h \ 23 | include/vhd-uuid.h 24 | 25 | 26 | include_HEADERS += include/libvhd.h include/vhd-uuid.h include/vhd.h 27 | 28 | # libvhd 29 | LIBVHD_VERS=@LIBVHD_VERSION_MAJOR@:@LIBVHD_VERSION_MINOR@:@LIBVHD_VERSION_SUBMINOR@ 30 | VHD_VERS=@LIBVHD_VERSION_MAJOR@.@LIBVHD_VERSION_MINOR@.@LIBVHD_VERSION_SUBMINOR@ 31 | lib_LTLIBRARIES += libvhd.la 32 | libvhd_la_SOURCES = lib/libvhd.c \ 33 | lib/vhd-util-uuid.c \ 34 | lib/relative-path.c 35 | libvhd_la_LDFLAGS = -version-info ${LIBVHD_VERS} 36 | 37 | # vhd-update 38 | bin_PROGRAMS += vhd-update 39 | vhd_update_SOURCES = tools/vhd-update/vhd-update.c \ 40 | tools/common/atomicio.c \ 41 | tools/common/libvhd-journal.c 42 | 43 | # vhd-util 44 | bin_PROGRAMS += vhd-util 45 | vhd_util_SOURCES = tools/vhd-util/vhd-util.c \ 46 | tools/vhd-util/vhd-util-check.c \ 47 | tools/vhd-util/vhd-util-fill.c \ 48 | tools/vhd-util/vhd-util-read.c \ 49 | tools/vhd-util/vhd-util-revert.c \ 50 | tools/vhd-util/vhd-util-snapshot.c \ 51 | tools/vhd-util/vhd-util-coalesce.c \ 52 | tools/vhd-util/vhd-util-modify.c \ 53 | tools/vhd-util/vhd-util-repair.c \ 54 | tools/vhd-util/vhd-util-scan.c \ 55 | tools/vhd-util/vhd-util-create.c \ 56 | tools/vhd-util/vhd-util-query.c \ 57 | tools/vhd-util/vhd-util-resize.c \ 58 | tools/vhd-util/vhd-util-set-field.c \ 59 | tools/vhd-util/lvm-util.c \ 60 | tools/common/atomicio.c \ 61 | tools/common/libvhd-journal.c 62 | 63 | distclean-local: 64 | rm -rf configure Makefile.in aclocal.m4 autom4te.cache config m4 vhd-${VHD_VERS} vhd-${VHD_VERS}.tar.gz 65 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This repository contains source code that implements the VHD 2 | (Virtual Hard Drive) file format. Contained within is a C library and 3 | associated tools. 4 | 5 | This code originated from the Xen hypervisor source code tree, found under the 6 | tools/blktap2/vhd directory. 7 | 8 | According to the COPYING file found in the root of the Xen source code tree 9 | (which I've duplicated in this repo), most or all of the code contained here 10 | is licensed under GNU GPLv2. Please read 'COPYING' for more detail. 11 | 12 | === 13 | 14 | libuuid and associated header files are required for building. If building on 15 | Debian or Ubuntu, apt-get install uuid-dev. 16 | 17 | Code can be built by: 18 | 19 | 1) sh autogen.sh 20 | 2) ./configure 21 | 3) make 22 | 23 | To install the library, headers, and tools, 'make install'. 24 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | aclocal 6 | libtoolize -c 7 | automake -c --add-missing 8 | autoconf 9 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([VHD Library and Tools], 2 | [1.0.0], 3 | [comstud@gmail.com], 4 | [vhd], 5 | [http://github.com/comstud/vhd]) 6 | AC_CONFIG_SRCDIR([lib/libvhd.c]) 7 | AC_CONFIG_AUX_DIR(config) 8 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 9 | AC_PROG_CC 10 | AM_PROG_CC_C_O 11 | # Automake 1.12 requires AM_PROG_AR, but older versions don't know it. 12 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 13 | AC_PROG_LIBTOOL 14 | AC_CONFIG_MACRO_DIR([m4]) 15 | 16 | AC_CHECK_HEADERS([uuid/uuid.h], [], [ 17 | echo "" 18 | echo "Missing uuid/uuid.h. Please install uuid-dev." 19 | echo "" 20 | exit 1 21 | ]) 22 | 23 | AC_CHECK_LIB(uuid, uuid_generate) 24 | 25 | LIBVHD_VERSION_MAJOR=1 26 | LIBVHD_VERSION_MINOR=0 27 | LIBVHD_VERSION_SUBMINOR=0 28 | 29 | AC_SUBST(LIBVHD_VERSION_MAJOR) 30 | AC_SUBST(LIBVHD_VERSION_MINOR) 31 | AC_SUBST(LIBVHD_VERSION_SUBMINOR) 32 | 33 | AC_CONFIG_FILES(Makefile) 34 | AC_OUTPUT 35 | 36 | echo "" 37 | echo "Configuration summary for $PACKAGE_NAME $PACKAGE_VERSION:" 38 | echo " * Installation prefix: $prefix" 39 | echo " * System type: $host_vendor-$host_os" 40 | echo " * Host CPU: $host_cpu" 41 | echo " * C++ Compiler: $CXX_VERSION" 42 | echo " * Assertions enabled: $ac_cv_assert" 43 | echo " * Debug enabled: $with_debug" 44 | echo " * Profiling enabled: $ac_profiling" 45 | echo " * Coverage enabled: $ac_coverage" 46 | echo " * Warnings as errors: $ac_cv_warnings_as_errors" 47 | echo "" 48 | -------------------------------------------------------------------------------- /include/atomicio.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: atomicio.h,v 1.6 2005/05/24 17:32:43 avsm Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* 29 | * Ensure all of data on socket comes through. f==read || f==vwrite 30 | */ 31 | size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); 32 | 33 | #define vwrite (ssize_t (*)(int, void *, size_t))write 34 | -------------------------------------------------------------------------------- /include/libvhd-journal.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #ifndef _VHD_JOURNAL_H_ 28 | #define _VHD_JOURNAL_H_ 29 | 30 | #include 31 | 32 | #include "libvhd.h" 33 | 34 | #define VHD_JOURNAL_METADATA 0x01 35 | #define VHD_JOURNAL_DATA 0x02 36 | 37 | #define VHD_JOURNAL_HEADER_COOKIE "vjournal" 38 | #define VHD_JOURNAL_ENTRY_COOKIE 0xaaaa12344321aaaa 39 | 40 | typedef struct vhd_journal_header { 41 | char cookie[8]; 42 | vhd_uuid_t uuid; 43 | uint64_t vhd_footer_offset; 44 | uint32_t journal_data_entries; 45 | uint32_t journal_metadata_entries; 46 | uint64_t journal_data_offset; 47 | uint64_t journal_metadata_offset; 48 | uint64_t journal_eof; 49 | char pad[448]; 50 | } vhd_journal_header_t; 51 | 52 | typedef struct vhd_journal { 53 | char *jname; 54 | int jfd; 55 | int is_block; /* is jfd a block device */ 56 | vhd_journal_header_t header; 57 | vhd_context_t vhd; 58 | } vhd_journal_t; 59 | 60 | int vhd_journal_create(vhd_journal_t *, const char *file, const char *jfile); 61 | int vhd_journal_open(vhd_journal_t *, const char *file, const char *jfile); 62 | int vhd_journal_add_block(vhd_journal_t *, uint32_t block, char mode); 63 | int vhd_journal_commit(vhd_journal_t *); 64 | int vhd_journal_revert(vhd_journal_t *); 65 | int vhd_journal_close(vhd_journal_t *); 66 | int vhd_journal_remove(vhd_journal_t *); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /include/libvhd.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #ifndef _VHD_LIB_H_ 28 | #define _VHD_LIB_H_ 29 | 30 | #include 31 | #if defined(__linux__) 32 | #include 33 | #include 34 | #elif defined(__NetBSD__) 35 | #include 36 | #include 37 | #endif 38 | 39 | #include "vhd-uuid.h" 40 | #include "vhd.h" 41 | 42 | #ifndef O_LARGEFILE 43 | #define O_LARGEFILE 0 44 | #endif 45 | 46 | #if BYTE_ORDER == LITTLE_ENDIAN 47 | #if defined(__linux__) 48 | #define BE16_IN(foo) (*(foo)) = bswap_16(*(foo)) 49 | #define BE32_IN(foo) (*(foo)) = bswap_32(*(foo)) 50 | #define BE64_IN(foo) (*(foo)) = bswap_64(*(foo)) 51 | #define BE16_OUT(foo) (*(foo)) = bswap_16(*(foo)) 52 | #define BE32_OUT(foo) (*(foo)) = bswap_32(*(foo)) 53 | #define BE64_OUT(foo) (*(foo)) = bswap_64(*(foo)) 54 | #elif defined(__NetBSD__) 55 | #define BE16_IN(foo) (*(foo)) = bswap16(*(foo)) 56 | #define BE32_IN(foo) (*(foo)) = bswap32(*(foo)) 57 | #define BE64_IN(foo) (*(foo)) = bswap64(*(foo)) 58 | #define BE16_OUT(foo) (*(foo)) = bswap16(*(foo)) 59 | #define BE32_OUT(foo) (*(foo)) = bswap32(*(foo)) 60 | #define BE64_OUT(foo) (*(foo)) = bswap64(*(foo)) 61 | #endif 62 | #else 63 | #define BE16_IN(foo) 64 | #define BE32_IN(foo) 65 | #define BE64_IN(foo) 66 | #define BE32_OUT(foo) 67 | #define BE32_OUT(foo) 68 | #define BE64_OUT(foo) 69 | #endif 70 | 71 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 72 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 73 | 74 | #define VHD_MAX_NAME_LEN 1024 75 | 76 | #define VHD_BLOCK_SHIFT 21 77 | #define VHD_BLOCK_SIZE (1ULL << VHD_BLOCK_SHIFT) 78 | 79 | #define UTF_16 "UTF-16" 80 | #define UTF_16LE "UTF-16LE" 81 | #define UTF_16BE "UTF-16BE" 82 | 83 | #define VHD_OPEN_RDONLY 0x00001 84 | #define VHD_OPEN_RDWR 0x00002 85 | #define VHD_OPEN_FAST 0x00004 86 | #define VHD_OPEN_STRICT 0x00008 87 | #define VHD_OPEN_IGNORE_DISABLED 0x00010 88 | 89 | #define VHD_FLAG_CREAT_PARENT_RAW 0x00001 90 | 91 | #define vhd_flag_set(word, flag) ((word) |= (flag)) 92 | #define vhd_flag_clear(word, flag) ((word) &= ~(flag)) 93 | #define vhd_flag_test(word, flag) ((word) & (flag)) 94 | 95 | 96 | #define ENABLE_FAILURE_TESTING 97 | #define FAIL_REPARENT_BEGIN 0 98 | #define FAIL_REPARENT_LOCATOR 1 99 | #define FAIL_REPARENT_END 2 100 | #define FAIL_RESIZE_BEGIN 3 101 | #define FAIL_RESIZE_DATA_MOVED 4 102 | #define FAIL_RESIZE_METADATA_MOVED 5 103 | #define FAIL_RESIZE_END 6 104 | #define NUM_FAIL_TESTS 7 105 | 106 | #ifdef ENABLE_FAILURE_TESTING 107 | #define TEST_FAIL_AT(point) \ 108 | if (TEST_FAIL[point]) { \ 109 | printf("Failing at %s\n", ENV_VAR_FAIL[point]); exit(EINVAL); } 110 | #define TEST_FAIL_EXTERN_VARS \ 111 | extern const char* ENV_VAR_FAIL[]; \ 112 | extern int TEST_FAIL[]; 113 | #else 114 | #define TEST_FAIL_AT(point) 115 | #define TEST_FAIL_EXTERN_VARS 116 | #endif // ENABLE_FAILURE_TESTING 117 | 118 | 119 | static const char VHD_POISON_COOKIE[] = "v_poison"; 120 | 121 | typedef struct hd_ftr vhd_footer_t; 122 | typedef struct dd_hdr vhd_header_t; 123 | typedef struct vhd_bat vhd_bat_t; 124 | typedef struct vhd_batmap vhd_batmap_t; 125 | typedef struct dd_batmap_hdr vhd_batmap_header_t; 126 | typedef struct prt_loc vhd_parent_locator_t; 127 | typedef struct vhd_context vhd_context_t; 128 | typedef uint32_t vhd_flag_creat_t; 129 | 130 | struct vhd_bat { 131 | uint32_t spb; 132 | uint32_t entries; 133 | uint32_t *bat; 134 | }; 135 | 136 | struct vhd_batmap { 137 | vhd_batmap_header_t header; 138 | char *map; 139 | }; 140 | 141 | struct vhd_context { 142 | int fd; 143 | char *file; 144 | int oflags; 145 | int is_block; 146 | 147 | uint32_t spb; 148 | uint32_t bm_secs; 149 | 150 | vhd_header_t header; 151 | vhd_footer_t footer; 152 | vhd_bat_t bat; 153 | vhd_batmap_t batmap; 154 | }; 155 | 156 | static inline uint32_t 157 | secs_round_up(uint64_t bytes) 158 | { 159 | return ((bytes + (VHD_SECTOR_SIZE - 1)) >> VHD_SECTOR_SHIFT); 160 | } 161 | 162 | static inline uint32_t 163 | secs_round_up_no_zero(uint64_t bytes) 164 | { 165 | return (secs_round_up(bytes) ? : 1); 166 | } 167 | 168 | static inline uint64_t 169 | vhd_sectors_to_bytes(uint64_t sectors) 170 | { 171 | return sectors << VHD_SECTOR_SHIFT; 172 | } 173 | 174 | static inline uint64_t 175 | vhd_bytes_padded(uint64_t bytes) 176 | { 177 | return vhd_sectors_to_bytes(secs_round_up_no_zero(bytes)); 178 | } 179 | 180 | static inline int 181 | vhd_type_dynamic(vhd_context_t *ctx) 182 | { 183 | return (ctx->footer.type == HD_TYPE_DYNAMIC || 184 | ctx->footer.type == HD_TYPE_DIFF); 185 | } 186 | 187 | static inline int 188 | vhd_creator_tapdisk(vhd_context_t *ctx) 189 | { 190 | return !strncmp(ctx->footer.crtr_app, "tap", 3); 191 | } 192 | 193 | static inline int 194 | vhd_disabled(vhd_context_t *ctx) 195 | { 196 | return (!memcmp(ctx->footer.cookie, 197 | VHD_POISON_COOKIE, sizeof(ctx->footer.cookie))); 198 | } 199 | 200 | static inline size_t 201 | vhd_parent_locator_size(vhd_parent_locator_t *loc) 202 | { 203 | /* 204 | * MICROSOFT_COMPAT 205 | * data_space *should* be in sectors, 206 | * but sometimes we find it in bytes 207 | */ 208 | if (loc->data_space < 512) 209 | return vhd_sectors_to_bytes(loc->data_space); 210 | else if (loc->data_space % 512 == 0) 211 | return loc->data_space; 212 | else 213 | return 0; 214 | } 215 | 216 | static inline int 217 | vhd_parent_raw(vhd_context_t *ctx) 218 | { 219 | return vhd_uuid_is_nil(&ctx->header.prt_uuid); 220 | } 221 | 222 | void libvhd_set_log_level(int); 223 | 224 | int vhd_test_file_fixed(const char *, int *); 225 | 226 | uint32_t vhd_time(time_t time); 227 | size_t vhd_time_to_string(uint32_t timestamp, char *target); 228 | uint32_t vhd_chs(uint64_t size); 229 | 230 | uint32_t vhd_checksum_footer(vhd_footer_t *); 231 | uint32_t vhd_checksum_header(vhd_header_t *); 232 | uint32_t vhd_checksum_batmap(vhd_batmap_t *); 233 | 234 | void vhd_footer_in(vhd_footer_t *); 235 | void vhd_footer_out(vhd_footer_t *); 236 | void vhd_header_in(vhd_header_t *); 237 | void vhd_header_out(vhd_header_t *); 238 | void vhd_bat_in(vhd_bat_t *); 239 | void vhd_bat_out(vhd_bat_t *); 240 | void vhd_batmap_header_in(vhd_batmap_t *); 241 | void vhd_batmap_header_out(vhd_batmap_t *); 242 | 243 | int vhd_validate_footer(vhd_footer_t *footer); 244 | int vhd_validate_header(vhd_header_t *header); 245 | int vhd_validate_batmap_header(vhd_batmap_t *batmap); 246 | int vhd_validate_batmap(vhd_batmap_t *batmap); 247 | int vhd_validate_platform_code(uint32_t code); 248 | 249 | int vhd_open(vhd_context_t *, const char *file, int flags); 250 | void vhd_close(vhd_context_t *); 251 | int vhd_create(const char *name, uint64_t bytes, int type, vhd_flag_creat_t); 252 | /* vhd_snapshot: the bytes parameter is optional and can be 0 if the snapshot 253 | * is to have the same size as the (first non-empty) parent */ 254 | int vhd_snapshot(const char *snapshot, uint64_t bytes, const char *parent, 255 | vhd_flag_creat_t); 256 | 257 | int vhd_hidden(vhd_context_t *, int *); 258 | int vhd_chain_depth(vhd_context_t *, int *); 259 | 260 | off_t vhd_position(vhd_context_t *); 261 | int vhd_seek(vhd_context_t *, off_t, int); 262 | int vhd_read(vhd_context_t *, void *, size_t); 263 | int vhd_write(vhd_context_t *, void *, size_t); 264 | 265 | int vhd_offset(vhd_context_t *, uint32_t, uint32_t *); 266 | 267 | int vhd_end_of_headers(vhd_context_t *ctx, off_t *off); 268 | int vhd_end_of_data(vhd_context_t *ctx, off_t *off); 269 | int vhd_batmap_header_offset(vhd_context_t *ctx, off_t *off); 270 | 271 | int vhd_get_header(vhd_context_t *); 272 | int vhd_get_footer(vhd_context_t *); 273 | int vhd_get_bat(vhd_context_t *); 274 | int vhd_get_batmap(vhd_context_t *); 275 | 276 | void vhd_put_header(vhd_context_t *); 277 | void vhd_put_footer(vhd_context_t *); 278 | void vhd_put_bat(vhd_context_t *); 279 | void vhd_put_batmap(vhd_context_t *); 280 | 281 | int vhd_has_batmap(vhd_context_t *); 282 | int vhd_batmap_test(vhd_context_t *, vhd_batmap_t *, uint32_t); 283 | void vhd_batmap_set(vhd_context_t *, vhd_batmap_t *, uint32_t); 284 | void vhd_batmap_clear(vhd_context_t *, vhd_batmap_t *, uint32_t); 285 | 286 | int vhd_get_phys_size(vhd_context_t *, off_t *); 287 | int vhd_set_phys_size(vhd_context_t *, off_t); 288 | 289 | int vhd_bitmap_test(vhd_context_t *, char *, uint32_t); 290 | void vhd_bitmap_set(vhd_context_t *, char *, uint32_t); 291 | void vhd_bitmap_clear(vhd_context_t *, char *, uint32_t); 292 | 293 | int vhd_parent_locator_count(vhd_context_t *); 294 | int vhd_parent_locator_get(vhd_context_t *, char **); 295 | int vhd_parent_locator_read(vhd_context_t *, vhd_parent_locator_t *, char **); 296 | int vhd_find_parent(vhd_context_t *, const char *, char **); 297 | int vhd_parent_locator_write_at(vhd_context_t *, const char *, 298 | off_t, uint32_t, size_t, 299 | vhd_parent_locator_t *); 300 | 301 | int vhd_header_decode_parent(vhd_context_t *, vhd_header_t *, char **); 302 | int vhd_change_parent(vhd_context_t *, char *parent_path, int raw); 303 | 304 | int vhd_read_footer(vhd_context_t *, vhd_footer_t *); 305 | int vhd_read_footer_at(vhd_context_t *, vhd_footer_t *, off_t); 306 | int vhd_read_footer_strict(vhd_context_t *, vhd_footer_t *); 307 | int vhd_read_header(vhd_context_t *, vhd_header_t *); 308 | int vhd_read_header_at(vhd_context_t *, vhd_header_t *, off_t); 309 | int vhd_read_bat(vhd_context_t *, vhd_bat_t *); 310 | int vhd_read_batmap(vhd_context_t *, vhd_batmap_t *); 311 | int vhd_read_bitmap(vhd_context_t *, uint32_t block, char **bufp); 312 | int vhd_read_block(vhd_context_t *, uint32_t block, char **bufp); 313 | 314 | int vhd_write_footer(vhd_context_t *, vhd_footer_t *); 315 | int vhd_write_footer_at(vhd_context_t *, vhd_footer_t *, off_t); 316 | int vhd_write_header(vhd_context_t *, vhd_header_t *); 317 | int vhd_write_header_at(vhd_context_t *, vhd_header_t *, off_t); 318 | int vhd_write_bat(vhd_context_t *, vhd_bat_t *); 319 | int vhd_write_batmap(vhd_context_t *, vhd_batmap_t *); 320 | int vhd_write_bitmap(vhd_context_t *, uint32_t block, char *bitmap); 321 | int vhd_write_block(vhd_context_t *, uint32_t block, char *data); 322 | 323 | int vhd_io_read(vhd_context_t *, char *, uint64_t, uint32_t); 324 | int vhd_io_write(vhd_context_t *, char *, uint64_t, uint32_t); 325 | 326 | #endif 327 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * list.h 3 | * 4 | * This is a subset of linux's list.h intended to be used in user-space. 5 | * XXX The namespace conflicts with NetBSD's 6 | * 7 | */ 8 | 9 | #ifndef __LIST_H__ 10 | #define __LIST_H__ 11 | 12 | #define LIST_POISON1 ((void *) 0x00100100) 13 | #define LIST_POISON2 ((void *) 0x00200200) 14 | 15 | struct list_head { 16 | struct list_head *next, *prev; 17 | }; 18 | 19 | /* XXX workaround for conflicts. The list API should use its own 20 | * namespace prefix, i.e. BLK_ 21 | */ 22 | #ifdef LIST_HEAD_INIT 23 | #undef LIST_HEAD_INIT 24 | #endif 25 | #ifndef LIST_HEAD 26 | #undef LIST_HEAD 27 | #endif 28 | 29 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 30 | 31 | #define LIST_HEAD(name) \ 32 | struct list_head name = LIST_HEAD_INIT(name) 33 | 34 | static inline void INIT_LIST_HEAD(struct list_head *list) 35 | { 36 | list->next = list; 37 | list->prev = list; 38 | } 39 | 40 | static inline void __list_add(struct list_head *new, 41 | struct list_head *prev, 42 | struct list_head *next) 43 | { 44 | next->prev = new; 45 | new->next = next; 46 | new->prev = prev; 47 | prev->next = new; 48 | } 49 | 50 | static inline void list_add(struct list_head *new, struct list_head *head) 51 | { 52 | __list_add(new, head, head->next); 53 | } 54 | 55 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 56 | { 57 | __list_add(new, head->prev, head); 58 | } 59 | 60 | static inline void __list_del(struct list_head * prev, struct list_head * next) 61 | { 62 | next->prev = prev; 63 | prev->next = next; 64 | } 65 | 66 | static inline void list_del(struct list_head *entry) 67 | { 68 | __list_del(entry->prev, entry->next); 69 | entry->next = LIST_POISON1; 70 | entry->prev = LIST_POISON2; 71 | } 72 | 73 | static inline void list_del_init(struct list_head *entry) 74 | { 75 | __list_del(entry->prev, entry->next); 76 | INIT_LIST_HEAD(entry); 77 | } 78 | 79 | static inline int list_empty(const struct list_head *head) 80 | { 81 | return head->next == head; 82 | } 83 | 84 | static inline int list_is_last(const struct list_head *list, 85 | const struct list_head *head) 86 | { 87 | return list->next == head; 88 | } 89 | 90 | static inline void __list_splice(const struct list_head *list, 91 | struct list_head *prev, 92 | struct list_head *next) 93 | { 94 | struct list_head *first = list->next; 95 | struct list_head *last = list->prev; 96 | 97 | first->prev = prev; 98 | prev->next = first; 99 | 100 | last->next = next; 101 | next->prev = last; 102 | } 103 | 104 | static inline void list_splice(const struct list_head *list, 105 | struct list_head *head) 106 | { 107 | if (!list_empty(list)) 108 | __list_splice(list, head, head->next); 109 | } 110 | 111 | #define list_entry(ptr, type, member) \ 112 | ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 113 | 114 | #define list_for_each_entry(pos, head, member) \ 115 | for (pos = list_entry((head)->next, typeof(*pos), member); \ 116 | &pos->member != (head); \ 117 | pos = list_entry(pos->member.next, typeof(*pos), member)) 118 | 119 | #define list_for_each_entry_safe(pos, n, head, member) \ 120 | for (pos = list_entry((head)->next, typeof(*pos), member), \ 121 | n = list_entry(pos->member.next, typeof(*pos), member); \ 122 | &pos->member != (head); \ 123 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) 124 | 125 | #endif /* __LIST_H__ */ 126 | -------------------------------------------------------------------------------- /include/lvm-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, XenSource Inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of XenSource Inc. nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software 14 | * without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #ifndef _LVM_UTIL_H_ 29 | #define _LVM_UTIL_H_ 30 | 31 | #include 32 | 33 | #define MAX_NAME_SIZE 256 34 | 35 | #define LVM_SEG_TYPE_LINEAR 1 36 | #define LVM_SEG_TYPE_UNKNOWN 2 37 | 38 | struct lv_segment { 39 | uint8_t type; 40 | char device[MAX_NAME_SIZE]; 41 | uint64_t pe_start; 42 | uint64_t pe_size; 43 | }; 44 | 45 | struct lv { 46 | char name[MAX_NAME_SIZE]; 47 | uint64_t size; 48 | uint32_t segments; 49 | struct lv_segment first_segment; 50 | }; 51 | 52 | struct pv { 53 | char name[MAX_NAME_SIZE]; 54 | uint64_t start; 55 | }; 56 | 57 | struct vg { 58 | char name[MAX_NAME_SIZE]; 59 | uint64_t extent_size; 60 | 61 | int pv_cnt; 62 | struct pv *pvs; 63 | 64 | int lv_cnt; 65 | struct lv *lvs; 66 | }; 67 | 68 | int lvm_scan_vg(const char *vg_name, struct vg *vg); 69 | void lvm_free_vg(struct vg *vg); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /include/relative-path.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #ifndef _RELATIVE_PATH_H_ 28 | #define _RELATIVE_PATH_H_ 29 | 30 | #include 31 | 32 | #define DELIMITER '/' 33 | #define MAX_NAME_LEN 1000 34 | 35 | #define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a) 36 | 37 | /* 38 | * returns a relative path from @src to @dest 39 | * result should be freed 40 | */ 41 | char *relative_path_to(char *src, char *dest, int *err); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/vhd-util.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #ifndef _VHD_UTIL_H_ 28 | #define _VHD_UTIL_H_ 29 | 30 | int vhd_util_create(int argc, char **argv); 31 | int vhd_util_snapshot(int argc, char **argv); 32 | int vhd_util_query(int argc, char **argv); 33 | int vhd_util_read(int argc, char **argv); 34 | int vhd_util_set_field(int argc, char **argv); 35 | int vhd_util_repair(int argc, char **argv); 36 | int vhd_util_fill(int argc, char **argv); 37 | int vhd_util_resize(int argc, char **argv); 38 | int vhd_util_coalesce(int argc, char **argv); 39 | int vhd_util_modify(int argc, char **argv); 40 | int vhd_util_scan(int argc, char **argv); 41 | int vhd_util_check(int argc, char **argv); 42 | int vhd_util_revert(int argc, char **argv); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/vhd-uuid.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #ifndef __BLKTAP2_VHD_UUID_H__ 28 | #define __BLKTAP2_VHD_UUID_H__ 29 | 30 | #if defined(__linux__) 31 | 32 | #include 33 | typedef struct { 34 | uuid_t uuid; 35 | } vhd_uuid_t; 36 | 37 | #elif defined(__NetBSD__) 38 | 39 | #include 40 | 41 | typedef uuid_t vhd_uuid_t; 42 | 43 | #else 44 | 45 | #error "Please update vhd-uuid.h for your OS" 46 | 47 | #endif 48 | 49 | int vhd_uuid_is_nil(vhd_uuid_t *uuid); 50 | 51 | void vhd_uuid_generate(vhd_uuid_t *uuid); 52 | 53 | void vhd_uuid_to_string(vhd_uuid_t *uuid, char *out, size_t size); 54 | 55 | void vhd_uuid_from_string(vhd_uuid_t *uuid, const char *in); 56 | 57 | void vhd_uuid_copy(vhd_uuid_t *dst, vhd_uuid_t *src); 58 | 59 | void vhd_uuid_clear(vhd_uuid_t *uuid); 60 | 61 | int vhd_uuid_compare(vhd_uuid_t *uuid1, vhd_uuid_t *uuid2); 62 | 63 | #endif /* __BLKTAP2_VHD_UUID_H__ */ 64 | -------------------------------------------------------------------------------- /include/vhd.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #ifndef __VHD_H__ 28 | #define __VHD_H__ 29 | 30 | #include 31 | 32 | typedef uint32_t u32; 33 | typedef uint64_t u64; 34 | 35 | #define DEBUG 1 36 | 37 | /* ---------------------------------------------------------------------- */ 38 | /* General definitions. */ 39 | /* ---------------------------------------------------------------------- */ 40 | 41 | #define VHD_SECTOR_SIZE 512 42 | #define VHD_SECTOR_SHIFT 9 43 | 44 | /* ---------------------------------------------------------------------- */ 45 | /* This is the generic disk footer, used by all disks. */ 46 | /* ---------------------------------------------------------------------- */ 47 | 48 | struct hd_ftr { 49 | char cookie[8]; /* Identifies original creator of the disk */ 50 | u32 features; /* Feature Support -- see below */ 51 | u32 ff_version; /* (major,minor) version of disk file */ 52 | u64 data_offset; /* Abs. offset from SOF to next structure */ 53 | u32 timestamp; /* Creation time. secs since 1/1/2000GMT */ 54 | char crtr_app[4]; /* Creator application */ 55 | u32 crtr_ver; /* Creator version (major,minor) */ 56 | u32 crtr_os; /* Creator host OS */ 57 | u64 orig_size; /* Size at creation (bytes) */ 58 | u64 curr_size; /* Current size of disk (bytes) */ 59 | u32 geometry; /* Disk geometry */ 60 | u32 type; /* Disk type */ 61 | u32 checksum; /* 1's comp sum of this struct. */ 62 | vhd_uuid_t uuid; /* Unique disk ID, used for naming parents */ 63 | char saved; /* one-bit -- is this disk/VM in a saved state? */ 64 | char hidden; /* tapdisk-specific field: is this vdi hidden? */ 65 | char reserved[426]; /* padding */ 66 | }; 67 | 68 | /* VHD cookie string. */ 69 | static const char HD_COOKIE[9] = "conectix"; 70 | 71 | /* Feature fields in hd_ftr */ 72 | #define HD_NO_FEATURES 0x00000000 73 | #define HD_TEMPORARY 0x00000001 /* disk can be deleted on shutdown */ 74 | #define HD_RESERVED 0x00000002 /* NOTE: must always be set */ 75 | 76 | /* Version field in hd_ftr */ 77 | #define HD_FF_VERSION 0x00010000 78 | 79 | /* Known creator OS type fields in hd_ftr.crtr_os */ 80 | #define HD_CR_OS_WINDOWS 0x5769326B /* (Wi2k) */ 81 | #define HD_CR_OS_MACINTOSH 0x4D616320 /* (Mac ) */ 82 | 83 | /* 84 | * version 0.1: little endian bitmaps 85 | * version 1.1: big endian bitmaps; batmap 86 | * version 1.2: libvhd 87 | * version 1.3: batmap version bump to 1.2 88 | */ 89 | #define VHD_VERSION(major, minor) (((major) << 16) | ((minor) & 0x0000FFFF)) 90 | #define VHD_CURRENT_VERSION VHD_VERSION(1, 3) 91 | 92 | /* Disk geometry accessor macros. */ 93 | /* Geometry is a triple of (cylinders (2 bytes), tracks (1 byte), and 94 | * secotrs-per-track (1 byte)) 95 | */ 96 | #define GEOM_GET_CYLS(_g) (((_g) >> 16) & 0xffff) 97 | #define GEOM_GET_HEADS(_g) (((_g) >> 8) & 0xff) 98 | #define GEOM_GET_SPT(_g) ((_g) & 0xff) 99 | 100 | #define GEOM_ENCODE(_c, _h, _s) (((_c) << 16) | ((_h) << 8) | (_s)) 101 | 102 | /* type field in hd_ftr */ 103 | #define HD_TYPE_NONE 0 104 | #define HD_TYPE_FIXED 2 /* fixed-allocation disk */ 105 | #define HD_TYPE_DYNAMIC 3 /* dynamic disk */ 106 | #define HD_TYPE_DIFF 4 /* differencing disk */ 107 | 108 | /* String table for hd.type */ 109 | static const char *HD_TYPE_STR[7] = { 110 | "None", /* 0 */ 111 | "Reserved (deprecated)", /* 1 */ 112 | "Fixed hard disk", /* 2 */ 113 | "Dynamic hard disk", /* 3 */ 114 | "Differencing hard disk", /* 4 */ 115 | "Reserved (deprecated)", /* 5 */ 116 | "Reserved (deprecated)" /* 6 */ 117 | }; 118 | 119 | #define HD_TYPE_MAX 6 120 | 121 | struct prt_loc { 122 | u32 code; /* Platform code -- see defines below. */ 123 | u32 data_space; /* Number of 512-byte sectors to store locator */ 124 | u32 data_len; /* Actual length of parent locator in bytes */ 125 | u32 res; /* Must be zero */ 126 | u64 data_offset; /* Absolute offset of locator data (bytes) */ 127 | }; 128 | 129 | /* Platform Codes */ 130 | #define PLAT_CODE_NONE 0x0 131 | #define PLAT_CODE_WI2R 0x57693272 /* deprecated */ 132 | #define PLAT_CODE_WI2K 0x5769326B /* deprecated */ 133 | #define PLAT_CODE_W2RU 0x57327275 /* Windows relative path (UTF-16) */ 134 | #define PLAT_CODE_W2KU 0x57326B75 /* Windows absolute path (UTF-16) */ 135 | #define PLAT_CODE_MAC 0x4D616320 /* MacOS alias stored as a blob. */ 136 | #define PLAT_CODE_MACX 0x4D616358 /* File URL (UTF-8), see RFC 2396. */ 137 | 138 | /* ---------------------------------------------------------------------- */ 139 | /* This is the dynamic disk header. */ 140 | /* ---------------------------------------------------------------------- */ 141 | 142 | struct dd_hdr { 143 | char cookie[8]; /* Should contain "cxsparse" */ 144 | u64 data_offset; /* Byte offset of next record. (Unused) 0xffs */ 145 | u64 table_offset; /* Absolute offset to the BAT. */ 146 | u32 hdr_ver; /* Version of the dd_hdr (major,minor) */ 147 | u32 max_bat_size; /* Maximum number of entries in the BAT */ 148 | u32 block_size; /* Block size in bytes. Must be power of 2. */ 149 | u32 checksum; /* Header checksum. 1's comp of all fields. */ 150 | vhd_uuid_t prt_uuid; /* ID of the parent disk. */ 151 | u32 prt_ts; /* Modification time of the parent disk */ 152 | u32 res1; /* Reserved. */ 153 | char prt_name[512]; /* Parent unicode name. */ 154 | struct prt_loc loc[8]; /* Parent locator entries. */ 155 | char res2[256]; /* Reserved. */ 156 | }; 157 | 158 | /* VHD cookie string. */ 159 | static const char DD_COOKIE[9] = "cxsparse"; 160 | 161 | /* Version field in hd_ftr */ 162 | #define DD_VERSION 0x00010000 163 | 164 | /* Default blocksize is 2 meg. */ 165 | #define DD_BLOCKSIZE_DEFAULT 0x00200000 166 | 167 | #define DD_BLK_UNUSED 0xFFFFFFFF 168 | 169 | struct dd_batmap_hdr { 170 | char cookie[8]; /* should contain "tdbatmap" */ 171 | u64 batmap_offset; /* byte offset to batmap */ 172 | u32 batmap_size; /* batmap size in sectors */ 173 | u32 batmap_version; /* version of batmap */ 174 | u32 checksum; /* batmap checksum -- 1's complement of batmap */ 175 | }; 176 | 177 | static const char VHD_BATMAP_COOKIE[9] = "tdbatmap"; 178 | 179 | /* 180 | * version 1.1: signed char checksum 181 | */ 182 | #define VHD_BATMAP_VERSION(major, minor) (((major) << 16) | ((minor) & 0x0000FFFF)) 183 | #define VHD_BATMAP_CURRENT_VERSION VHD_BATMAP_VERSION(1, 2) 184 | 185 | /* Layout of a dynamic disk: 186 | * 187 | * +-------------------------------------------------+ 188 | * | Mirror image of HD footer (hd_ftr) (512 bytes) | 189 | * +-------------------------------------------------+ 190 | * | Sparse drive header (dd_hdr) (1024 bytes) | 191 | * +-------------------------------------------------+ 192 | * | BAT (Block allocation table) | 193 | * | - Array of absolute sector offsets into the | 194 | * | file (u32). | 195 | * | - Rounded up to a sector boundary. | 196 | * | - Unused entries are marked as 0xFFFFFFFF | 197 | * | - max entries in dd_hdr->max_bat_size | 198 | * +-------------------------------------------------+ 199 | * | Data Block 0 | 200 | * | Bitmap (padded to 512 byte sector boundary) | 201 | * | - each bit indicates whether the associated | 202 | * | sector within this block is used. | 203 | * | Data | 204 | * | - power-of-two multiple of sectors. | 205 | * | - default 2MB (4096 * 512) | 206 | * | - Any entries with zero in bitmap should be | 207 | * | zero on disk | 208 | * +-------------------------------------------------+ 209 | * | Data Block 1 | 210 | * +-------------------------------------------------+ 211 | * | ... | 212 | * +-------------------------------------------------+ 213 | * | Data Block n | 214 | * +-------------------------------------------------+ 215 | * | HD Footer (511 bytes) | 216 | * +-------------------------------------------------+ 217 | */ 218 | 219 | #endif 220 | -------------------------------------------------------------------------------- /lib/relative-path.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "relative-path.h" 33 | 34 | #define sfree(ptr) \ 35 | do { \ 36 | free(ptr); \ 37 | ptr = NULL; \ 38 | } while (0) 39 | 40 | /* 41 | * count number of tokens between DELIMETER characters 42 | */ 43 | static int 44 | count_nodes(char *path) 45 | { 46 | int i; 47 | char *tmp; 48 | 49 | if (!path) 50 | return 0; 51 | 52 | for (i = 0, tmp = path; *tmp != '\0'; tmp++) 53 | if (*tmp == DELIMITER) 54 | i++; 55 | 56 | return i; 57 | } 58 | 59 | /* 60 | * return copy of next node in @path, or NULL 61 | * @path is moved to the end of the next node 62 | * @err is set to -errno on failure 63 | * copy should be freed 64 | */ 65 | static char * 66 | next_node(char **path, int *err) 67 | { 68 | int ret; 69 | char *tmp, *start; 70 | 71 | if (!path || !*path) { 72 | *err = -EINVAL; 73 | return NULL; 74 | } 75 | 76 | *err = 0; 77 | start = *path; 78 | 79 | for (tmp = *path; *tmp != '\0'; tmp++) 80 | if (*tmp == DELIMITER) { 81 | int size; 82 | char *node; 83 | 84 | size = tmp - start + 1; 85 | node = malloc(size); 86 | if (!node) { 87 | *err = -ENOMEM; 88 | return NULL; 89 | } 90 | 91 | ret = snprintf(node, size, "%s", start); 92 | if (ret < 0) { 93 | free(node); 94 | *err = -EINVAL; 95 | return NULL; 96 | } 97 | 98 | *path = tmp; 99 | return node; 100 | } 101 | 102 | return NULL; 103 | } 104 | 105 | /* 106 | * count number of nodes in common betwee @to and @from 107 | * returns number of common nodes, or -errno on failure 108 | */ 109 | static int 110 | count_common_nodes(char *to, char *from) 111 | { 112 | int err, common; 113 | char *to_node, *from_node; 114 | 115 | if (!to || !from) 116 | return -EINVAL; 117 | 118 | err = 0; 119 | common = 0; 120 | to_node = NULL; 121 | from_node = NULL; 122 | 123 | do { 124 | to_node = next_node(&to, &err); 125 | if (err || !to_node) 126 | break; 127 | 128 | from_node = next_node(&from, &err); 129 | if (err || !from_node) 130 | break; 131 | 132 | if (strncmp(to_node, from_node, MAX_NAME_LEN)) 133 | break; 134 | 135 | ++to; 136 | ++from; 137 | ++common; 138 | sfree(to_node); 139 | sfree(from_node); 140 | 141 | } while (1); 142 | 143 | sfree(to_node); 144 | sfree(from_node); 145 | 146 | if (err) 147 | return err; 148 | 149 | return common; 150 | } 151 | 152 | /* 153 | * construct path of @count '../', './' if @count is zero, or NULL on error 154 | * result should be freed 155 | */ 156 | static char * 157 | up_nodes(int count) 158 | { 159 | char *path, *tmp; 160 | int i, ret, len, size; 161 | 162 | if (!count) 163 | return strdup("./"); 164 | 165 | len = strlen("../"); 166 | size = len * count; 167 | if (size >= MAX_NAME_LEN) 168 | return NULL; 169 | 170 | path = malloc(size + 1); 171 | if (!path) 172 | return NULL; 173 | 174 | tmp = path; 175 | for (i = 0; i < count; i++) { 176 | ret = sprintf(tmp, "../"); 177 | if (ret < 0 || ret != len) { 178 | free(path); 179 | return NULL; 180 | } 181 | tmp += ret; 182 | } 183 | 184 | return path; 185 | } 186 | 187 | /* 188 | * return pointer to @offset'th node of path or NULL on error 189 | */ 190 | static char * 191 | node_offset(char *from, int offset) 192 | { 193 | char *path; 194 | 195 | if (!from || !offset) 196 | return NULL; 197 | 198 | for (path = from; *path != '\0'; path++) { 199 | if (*path == DELIMITER) 200 | if (--offset == 0) 201 | return path + 1; 202 | } 203 | 204 | return NULL; 205 | } 206 | 207 | /* 208 | * return a relative path from @from to @to 209 | * result should be freed 210 | */ 211 | char * 212 | relative_path_to(char *from, char *to, int *err) 213 | { 214 | int from_nodes, common; 215 | char *to_absolute, *from_absolute; 216 | char *up, *common_target_path, *relative_path; 217 | 218 | *err = 0; 219 | up = NULL; 220 | to_absolute = NULL; 221 | from_absolute = NULL; 222 | relative_path = NULL; 223 | 224 | if (strnlen(to, MAX_NAME_LEN) == MAX_NAME_LEN || 225 | strnlen(from, MAX_NAME_LEN) == MAX_NAME_LEN) { 226 | EPRINTF("invalid input; max path length is %d\n", 227 | MAX_NAME_LEN); 228 | *err = -ENAMETOOLONG; 229 | return NULL; 230 | } 231 | 232 | to_absolute = realpath(to, NULL); 233 | if (!to_absolute) { 234 | EPRINTF("failed to get absolute path of %s\n", to); 235 | *err = -errno; 236 | goto out; 237 | } 238 | 239 | from_absolute = realpath(from, NULL); 240 | if (!from_absolute) { 241 | EPRINTF("failed to get absolute path of %s\n", from); 242 | *err = -errno; 243 | goto out; 244 | } 245 | 246 | if (strnlen(to_absolute, MAX_NAME_LEN) == MAX_NAME_LEN || 247 | strnlen(from_absolute, MAX_NAME_LEN) == MAX_NAME_LEN) { 248 | EPRINTF("invalid input; max path length is %d\n", 249 | MAX_NAME_LEN); 250 | *err = -ENAMETOOLONG; 251 | goto out; 252 | } 253 | 254 | /* count nodes in source path */ 255 | from_nodes = count_nodes(from_absolute); 256 | 257 | /* count nodes in common */ 258 | common = count_common_nodes(to_absolute + 1, from_absolute + 1); 259 | if (common < 0) { 260 | EPRINTF("failed to count common nodes of %s and %s: %d\n", 261 | to_absolute, from_absolute, common); 262 | *err = common; 263 | goto out; 264 | } 265 | 266 | /* move up to common node */ 267 | up = up_nodes(from_nodes - common - 1); 268 | if (!up) { 269 | EPRINTF("failed to allocate relative path for %s: %d\n", 270 | from_absolute, -ENOMEM); 271 | *err = -ENOMEM; 272 | goto out; 273 | } 274 | 275 | /* get path from common node to target */ 276 | common_target_path = node_offset(to_absolute, common + 1); 277 | if (!common_target_path) { 278 | EPRINTF("failed to find common target path to %s: %d\n", 279 | to_absolute, -EINVAL); 280 | *err = -EINVAL; 281 | goto out; 282 | } 283 | 284 | /* get relative path */ 285 | if (asprintf(&relative_path, "%s%s", up, common_target_path) == -1) { 286 | EPRINTF("failed to construct final path %s%s: %d\n", 287 | up, common_target_path, -ENOMEM); 288 | relative_path = NULL; 289 | *err = -ENOMEM; 290 | goto out; 291 | } 292 | 293 | out: 294 | sfree(up); 295 | sfree(to_absolute); 296 | sfree(from_absolute); 297 | 298 | return relative_path; 299 | } 300 | -------------------------------------------------------------------------------- /lib/vhd-util-uuid.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * Copyright (c) 2011, Citrix 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of XenSource Inc. nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 21 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #if defined(__linux__) 31 | 32 | #include 33 | 34 | typedef struct { 35 | uuid_t uuid; 36 | } vhd_uuid_t; 37 | 38 | int vhd_uuid_is_nil(vhd_uuid_t *uuid) 39 | { 40 | return uuid_is_null(uuid->uuid); 41 | } 42 | 43 | void vhd_uuid_generate(vhd_uuid_t *uuid) 44 | { 45 | uuid_generate(uuid->uuid); 46 | } 47 | 48 | void vhd_uuid_to_string(vhd_uuid_t *uuid, char *out, size_t size) 49 | { 50 | uuid_unparse(uuid->uuid, out); 51 | } 52 | 53 | void vhd_uuid_from_string(vhd_uuid_t *uuid, const char *in) 54 | { 55 | uuid_parse(in, uuid->uuid); 56 | } 57 | 58 | void vhd_uuid_copy(vhd_uuid_t *dst, vhd_uuid_t *src) 59 | { 60 | uuid_copy(dst->uuid, src->uuid); 61 | } 62 | 63 | void vhd_uuid_clear(vhd_uuid_t *uuid) 64 | { 65 | uuid_clear(uuid->uuid); 66 | } 67 | 68 | int vhd_uuid_compare(vhd_uuid_t *uuid1, vhd_uuid_t *uuid2) 69 | { 70 | return uuid_compare(uuid1->uuid, uuid2->uuid); 71 | } 72 | 73 | #elif defined(__NetBSD__) 74 | 75 | #include 76 | #include 77 | #include 78 | 79 | typedef uuid_t vhd_uuid_t; 80 | 81 | int vhd_uuid_is_nil(vhd_uuid_t *uuid) 82 | { 83 | uint32_t status; 84 | return uuid_is_nil((uuid_t *)uuid, &status); 85 | } 86 | 87 | void vhd_uuid_generate(vhd_uuid_t *uuid) 88 | { 89 | uint32_t status; 90 | uuid_create((uuid_t *)uuid, &status); 91 | } 92 | 93 | void vhd_uuid_to_string(vhd_uuid_t *uuid, char *out, size_t size) 94 | { 95 | uint32_t status; 96 | char *_out = NULL; 97 | uuid_to_string((uuid_t *)uuid, &_out, &status); 98 | strlcpy(out, _out, size); 99 | free(_out); 100 | } 101 | 102 | void vhd_uuid_from_string(vhd_uuid_t *uuid, const char *in) 103 | { 104 | uint32_t status; 105 | uuid_from_string(in, (uuid_t *)uuid, &status); 106 | } 107 | 108 | void vhd_uuid_copy(vhd_uuid_t *dst, vhd_uuid_t *src) 109 | { 110 | memcpy((uuid_t *)dst, (uuid_t *)src, sizeof(uuid_t)); 111 | } 112 | 113 | void vhd_uuid_clear(vhd_uuid_t *uuid) 114 | { 115 | memset((uuid_t *)uuid, 0, sizeof(uuid_t)); 116 | } 117 | 118 | int vhd_uuid_compare(vhd_uuid_t *uuid1, vhd_uuid_t *uuid2) 119 | { 120 | uint32_t status; 121 | return uuid_compare((uuid_t *)uuid1, (uuid_t *)uuid2, &status); 122 | } 123 | 124 | #else 125 | 126 | #error "Please update vhd-util-uuid.c for your OS" 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /tools/common/atomicio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 3 | * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include "atomicio.h" 30 | 31 | /* 32 | * ensure all of data on socket comes through. f==read || f==vwrite 33 | */ 34 | size_t 35 | atomicio(f, fd, _s, n) 36 | ssize_t (*f) (int, void *, size_t); 37 | int fd; 38 | void *_s; 39 | size_t n; 40 | { 41 | char *s = _s; 42 | size_t pos = 0; 43 | ssize_t res; 44 | 45 | while (n > pos) { 46 | res = (f) (fd, s + pos, n - pos); 47 | switch (res) { 48 | case -1: 49 | if (errno == EINTR || errno == EAGAIN) 50 | continue; 51 | return 0; 52 | case 0: 53 | errno = EPIPE; 54 | return pos; 55 | default: 56 | pos += (size_t)res; 57 | } 58 | } 59 | return (pos); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /tools/vhd-update/vhd-update.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | * Before updating a VHD file, we create a journal consisting of: 28 | * - all data at the beginning of the file, up to and including the BAT 29 | * - each allocated bitmap (existing at the same offset in the journal as 30 | * its corresponding bitmap in the original file) 31 | * Updates are performed in place by writing appropriately 32 | * transformed versions of journaled bitmaps to the original file. 33 | */ 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "atomicio.h" 41 | #include "libvhd.h" 42 | #include "libvhd-journal.h" 43 | 44 | static void 45 | usage(void) 46 | { 47 | printf("usage: vhd-update <-n name> [-j existing journal] [-h]\n"); 48 | exit(EINVAL); 49 | } 50 | 51 | /* 52 | * update vhd creator version to reflect its new bitmap ordering 53 | */ 54 | static inline int 55 | update_creator_version(vhd_journal_t *journal) 56 | { 57 | journal->vhd.footer.crtr_ver = VHD_VERSION(1, 1); 58 | return vhd_write_footer(&journal->vhd, &journal->vhd.footer); 59 | } 60 | 61 | static int 62 | journal_bitmaps(vhd_journal_t *journal) 63 | { 64 | int i, err; 65 | 66 | for (i = 0; i < journal->vhd.bat.entries; i++) { 67 | err = vhd_journal_add_block(journal, i, VHD_JOURNAL_METADATA); 68 | if (err) 69 | return err; 70 | } 71 | 72 | return 0; 73 | } 74 | 75 | /* 76 | * older VHD bitmaps were little endian 77 | * and bits within a word were set from right to left 78 | */ 79 | static inline int 80 | old_test_bit(int nr, volatile void * addr) 81 | { 82 | return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >> 83 | (nr % (sizeof(unsigned long)*8))) & 1; 84 | } 85 | 86 | /* 87 | * new VHD bitmaps are big endian 88 | * and bits within a word are set from left to right 89 | */ 90 | #define BIT_MASK 0x80 91 | static inline void 92 | new_set_bit (int nr, volatile char *addr) 93 | { 94 | addr[nr >> 3] |= (BIT_MASK >> (nr & 7)); 95 | } 96 | 97 | static void 98 | convert_bitmap(char *in, char *out, int bytes) 99 | { 100 | int i; 101 | 102 | memset(out, 0, bytes); 103 | 104 | for (i = 0; i < bytes << 3; i++) 105 | if (old_test_bit(i, (void *)in)) 106 | new_set_bit(i, out); 107 | } 108 | 109 | static int 110 | update_vhd(vhd_journal_t *journal, int rollback) 111 | { 112 | int i, err; 113 | size_t size; 114 | char *buf, *converted; 115 | 116 | buf = NULL; 117 | converted = NULL; 118 | 119 | size = vhd_bytes_padded(journal->vhd.spb / 8); 120 | err = posix_memalign((void **)&converted, 512, size); 121 | if (err) { 122 | converted = NULL; 123 | goto out; 124 | } 125 | 126 | for (i = 0; i < journal->vhd.bat.entries; i++) { 127 | if (journal->vhd.bat.bat[i] == DD_BLK_UNUSED) 128 | continue; 129 | 130 | err = vhd_read_bitmap(&journal->vhd, i, &buf); 131 | if (err) 132 | goto out; 133 | 134 | if (rollback) 135 | memcpy(converted, buf, size); 136 | else 137 | convert_bitmap(buf, converted, size); 138 | 139 | free(buf); 140 | 141 | err = vhd_write_bitmap(&journal->vhd, i, converted); 142 | if (err) 143 | goto out; 144 | } 145 | 146 | err = 0; 147 | out: 148 | free(converted); 149 | return err; 150 | } 151 | 152 | static int 153 | open_journal(vhd_journal_t *journal, const char *file, const char *jfile) 154 | { 155 | int err; 156 | 157 | err = vhd_journal_create(journal, file, jfile); 158 | if (err) { 159 | printf("error creating journal for %s: %d\n", file, err); 160 | return err; 161 | } 162 | 163 | return 0; 164 | } 165 | 166 | static int 167 | close_journal(vhd_journal_t *journal, int err) 168 | { 169 | if (err) 170 | err = vhd_journal_revert(journal); 171 | else 172 | err = vhd_journal_commit(journal); 173 | 174 | if (err) 175 | return vhd_journal_close(journal); 176 | else 177 | return vhd_journal_remove(journal); 178 | } 179 | 180 | int 181 | main(int argc, char **argv) 182 | { 183 | char *file, *jfile; 184 | int c, err, rollback; 185 | vhd_journal_t journal; 186 | 187 | file = NULL; 188 | jfile = NULL; 189 | rollback = 0; 190 | 191 | while ((c = getopt(argc, argv, "n:j:rh")) != -1) { 192 | switch(c) { 193 | case 'n': 194 | file = optarg; 195 | break; 196 | case 'j': 197 | jfile = optarg; 198 | err = access(jfile, R_OK); 199 | if (err == -1) { 200 | printf("invalid journal arg %s\n", jfile); 201 | return -errno; 202 | } 203 | break; 204 | case 'r': 205 | /* add a rollback option for debugging which 206 | * pushes journalled bitmaps to original file 207 | * without transforming them */ 208 | rollback = 1; 209 | break; 210 | default: 211 | usage(); 212 | } 213 | } 214 | 215 | if (!file) 216 | usage(); 217 | 218 | if (rollback && !jfile) { 219 | printf("rollback requires a journal argument\n"); 220 | usage(); 221 | } 222 | 223 | err = open_journal(&journal, file, jfile); 224 | if (err) 225 | return err; 226 | 227 | if (!vhd_creator_tapdisk(&journal.vhd) || 228 | journal.vhd.footer.crtr_ver != VHD_VERSION(0, 1) || 229 | journal.vhd.footer.type == HD_TYPE_FIXED) { 230 | err = 0; 231 | goto out; 232 | } 233 | 234 | err = journal_bitmaps(&journal); 235 | if (err) { 236 | /* no changes to vhd file yet, 237 | * so close the journal and bail */ 238 | vhd_journal_close(&journal); 239 | return err; 240 | } 241 | 242 | err = update_vhd(&journal, rollback); 243 | if (err) { 244 | printf("update failed: %d; saving journal\n", err); 245 | goto out; 246 | } 247 | 248 | err = update_creator_version(&journal); 249 | if (err) { 250 | printf("failed to udpate creator version: %d\n", err); 251 | goto out; 252 | } 253 | 254 | err = 0; 255 | 256 | out: 257 | err = close_journal(&journal, err); 258 | return err; 259 | } 260 | -------------------------------------------------------------------------------- /tools/vhd-util/lvm-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, XenSource Inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of XenSource Inc. nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software 14 | * without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "lvm-util.h" 34 | 35 | #define _NAME "%255s" 36 | static char line[1024]; 37 | 38 | static inline int 39 | lvm_read_line(FILE *scan) 40 | { 41 | memset(line, 0, sizeof(line)); 42 | return (fscanf(scan, "%1023[^\n]", line) != 1); 43 | } 44 | 45 | static inline int 46 | lvm_next_line(FILE *scan) 47 | { 48 | return (fscanf(scan, "%1023[\n]", line) != 1); 49 | } 50 | 51 | static int 52 | lvm_copy_name(char *dst, const char *src, size_t size) 53 | { 54 | if (strnlen(src, size) == size) 55 | return -ENAMETOOLONG; 56 | 57 | strcpy(dst, src); 58 | return 0; 59 | } 60 | 61 | static int 62 | lvm_parse_pv(struct vg *vg, const char *name, int pvs, uint64_t start) 63 | { 64 | int i, err; 65 | struct pv *pv; 66 | 67 | pv = NULL; 68 | 69 | if (!vg->pvs) { 70 | vg->pvs = calloc(pvs, sizeof(struct pv)); 71 | if (!vg->pvs) 72 | return -ENOMEM; 73 | } 74 | 75 | for (i = 0; i < pvs; i++) { 76 | pv = vg->pvs + i; 77 | 78 | if (!pv->name[0]) 79 | break; 80 | 81 | if (!strcmp(pv->name, name)) 82 | return -EEXIST; 83 | } 84 | 85 | if (!pv) 86 | return -ENOENT; 87 | 88 | if (i == pvs) 89 | return -ENOMEM; 90 | 91 | err = lvm_copy_name(pv->name, name, sizeof(pv->name) - 1); 92 | if (err) 93 | return err; 94 | 95 | pv->start = start; 96 | return 0; 97 | } 98 | 99 | static int 100 | lvm_open_vg(const char *vgname, struct vg *vg) 101 | { 102 | FILE *scan; 103 | int i, err, pvs, lvs; 104 | char *cmd, pvname[256]; 105 | uint64_t size, pv_start; 106 | 107 | memset(vg, 0, sizeof(*vg)); 108 | 109 | err = asprintf(&cmd, "/usr/sbin/vgs %s --noheadings --nosuffix --units=b " 110 | "--options=vg_name,vg_extent_size,lv_count,pv_count," 111 | "pv_name,pe_start --unbuffered 2> /dev/null", vgname); 112 | if (err == -1) 113 | return -ENOMEM; 114 | 115 | errno = 0; 116 | scan = popen(cmd, "r"); 117 | if (!scan) { 118 | err = (errno ? -errno : ENOMEM); 119 | goto out; 120 | } 121 | 122 | for (;;) { 123 | if (lvm_read_line(scan)) 124 | break; 125 | 126 | err = -EINVAL; 127 | if (sscanf(line, _NAME" %"SCNu64" %d %d "_NAME" %"SCNu64, 128 | vg->name, &size, &lvs, &pvs, pvname, &pv_start) != 6) 129 | goto out; 130 | 131 | if (strcmp(vg->name, vgname)) 132 | goto out; 133 | 134 | err = lvm_parse_pv(vg, pvname, pvs, pv_start); 135 | if (err) 136 | goto out; 137 | 138 | if (lvm_next_line(scan)) 139 | break; 140 | } 141 | 142 | err = -EINVAL; 143 | if (strcmp(vg->name, vgname)) 144 | goto out; 145 | 146 | for (i = 0; i < pvs; i++) 147 | if (!vg->pvs[i].name[0]) 148 | goto out; 149 | 150 | err = -ENOMEM; 151 | vg->lvs = calloc(lvs, sizeof(struct lv)); 152 | if (!vg->lvs) 153 | goto out; 154 | 155 | err = 0; 156 | vg->lv_cnt = lvs; 157 | vg->pv_cnt = pvs; 158 | vg->extent_size = size; 159 | 160 | out: 161 | if (scan) 162 | pclose(scan); 163 | if (err) 164 | lvm_free_vg(vg); 165 | free(cmd); 166 | return err; 167 | } 168 | 169 | static int 170 | lvm_parse_lv_devices(struct vg *vg, struct lv_segment *seg, char *devices) 171 | { 172 | int i; 173 | uint64_t start, pe_start; 174 | 175 | for (i = 0; i < strlen(devices); i++) 176 | if (strchr(",()", devices[i])) 177 | devices[i] = ' '; 178 | 179 | if (sscanf(devices, _NAME" %"SCNu64, seg->device, &start) != 2) 180 | return -EINVAL; 181 | 182 | pe_start = -1; 183 | for (i = 0; i < vg->pv_cnt; i++) 184 | if (!strcmp(vg->pvs[i].name, seg->device)) { 185 | pe_start = vg->pvs[i].start; 186 | break; 187 | } 188 | 189 | if (pe_start == -1) 190 | return -EINVAL; 191 | 192 | seg->pe_start = (start * vg->extent_size) + pe_start; 193 | return 0; 194 | } 195 | 196 | static int 197 | lvm_scan_lvs(struct vg *vg) 198 | { 199 | char *cmd; 200 | FILE *scan; 201 | int i, err; 202 | 203 | err = asprintf(&cmd, "/usr/sbin/lvs %s --noheadings --nosuffix --units=b " 204 | "--options=lv_name,lv_size,segtype,seg_count,seg_start," 205 | "seg_size,devices --unbuffered 2> /dev/null", vg->name); 206 | if (err == -1) 207 | return -ENOMEM; 208 | 209 | errno = 0; 210 | scan = popen(cmd, "r"); 211 | if (!scan) { 212 | err = (errno ? -errno : -ENOMEM); 213 | goto out; 214 | } 215 | 216 | for (i = 0;;) { 217 | int segs; 218 | struct lv *lv; 219 | struct lv_segment seg; 220 | uint64_t size, seg_start; 221 | char type[32], name[256], dev[256], devices[1024]; 222 | 223 | if (i >= vg->lv_cnt) 224 | break; 225 | 226 | if (lvm_read_line(scan)) { 227 | vg->lv_cnt = i; 228 | break; 229 | } 230 | 231 | err = -EINVAL; 232 | lv = vg->lvs + i; 233 | 234 | if (sscanf(line, _NAME" %"SCNu64" %31s %u %"SCNu64" %"SCNu64" %1023s", 235 | name, &size, type, &segs, &seg_start, 236 | &seg.pe_size, devices) != 7) 237 | goto out; 238 | 239 | if (seg_start) 240 | goto next; 241 | 242 | if (!strcmp(type, "linear")) 243 | seg.type = LVM_SEG_TYPE_LINEAR; 244 | else 245 | seg.type = LVM_SEG_TYPE_UNKNOWN; 246 | 247 | if (lvm_parse_lv_devices(vg, &seg, devices)) 248 | goto out; 249 | 250 | i++; 251 | lv->size = size; 252 | lv->segments = segs; 253 | lv->first_segment = seg; 254 | 255 | err = lvm_copy_name(lv->name, name, sizeof(lv->name) - 1); 256 | if (err) 257 | goto out; 258 | err = -EINVAL; 259 | 260 | next: 261 | if (lvm_next_line(scan)) 262 | goto out; 263 | } 264 | 265 | err = 0; 266 | 267 | out: 268 | if (scan) 269 | pclose(scan); 270 | free(cmd); 271 | return err; 272 | } 273 | 274 | void 275 | lvm_free_vg(struct vg *vg) 276 | { 277 | free(vg->lvs); 278 | free(vg->pvs); 279 | memset(vg, 0, sizeof(*vg)); 280 | } 281 | 282 | int 283 | lvm_scan_vg(const char *vg_name, struct vg *vg) 284 | { 285 | int err; 286 | 287 | memset(vg, 0, sizeof(*vg)); 288 | 289 | err = lvm_open_vg(vg_name, vg); 290 | if (err) 291 | return err; 292 | 293 | err = lvm_scan_lvs(vg); 294 | if (err) { 295 | lvm_free_vg(vg); 296 | return err; 297 | } 298 | 299 | return 0; 300 | } 301 | 302 | #ifdef LVM_UTIL 303 | static int 304 | usage(void) 305 | { 306 | printf("usage: lvm-util \n"); 307 | exit(EINVAL); 308 | } 309 | 310 | int 311 | main(int argc, char **argv) 312 | { 313 | int i, err; 314 | struct vg vg; 315 | struct pv *pv; 316 | struct lv *lv; 317 | struct lv_segment *seg; 318 | 319 | if (argc != 2) 320 | usage(); 321 | 322 | err = lvm_scan_vg(argv[1], &vg); 323 | if (err) { 324 | printf("scan failed: %d\n", err); 325 | return (err >= 0 ? err : -err); 326 | } 327 | 328 | 329 | printf("vg %s: extent_size: %"PRIu64", pvs: %d, lvs: %d\n", 330 | vg.name, vg.extent_size, vg.pv_cnt, vg.lv_cnt); 331 | 332 | for (i = 0; i < vg.pv_cnt; i++) { 333 | pv = vg.pvs + i; 334 | printf("pv %s: start %"PRIu64"\n", pv->name, pv->start); 335 | } 336 | 337 | for (i = 0; i < vg.lv_cnt; i++) { 338 | lv = vg.lvs + i; 339 | seg = &lv->first_segment; 340 | printf("lv %s: size: %"PRIu64", segments: %u, type: %u, " 341 | "dev: %s, pe_start: %"PRIu64", pe_size: %"PRIu64"\n", 342 | lv->name, lv->size, lv->segments, seg->type, 343 | seg->device, seg->pe_start, seg->pe_size); 344 | } 345 | 346 | lvm_free_vg(&vg); 347 | return 0; 348 | } 349 | #endif 350 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-check.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "libvhd.h" 38 | #include "vhd-util.h" 39 | 40 | // allow the VHD timestamp to be at most this many seconds into the future to 41 | // account for time skew with NFS servers 42 | #define TIMESTAMP_MAX_SLACK 1800 43 | 44 | static int 45 | vhd_util_check_zeros(void *buf, size_t size) 46 | { 47 | int i; 48 | char *p; 49 | 50 | p = buf; 51 | for (i = 0; i < size; i++) 52 | if (p[i]) 53 | return i; 54 | 55 | return 0; 56 | } 57 | 58 | static int 59 | vhd_util_check_footer_opened(vhd_footer_t *footer) 60 | { 61 | int i, n; 62 | uint32_t *buf; 63 | 64 | buf = (uint32_t *)footer; 65 | n = sizeof(*footer) / sizeof(uint32_t); 66 | 67 | for (i = 0; i < n; i++) 68 | if (buf[i] != 0xc7c7c7c7) 69 | return 0; 70 | 71 | return 1; 72 | } 73 | 74 | static char * 75 | vhd_util_check_validate_footer(vhd_footer_t *footer) 76 | { 77 | int size; 78 | uint32_t checksum, now; 79 | 80 | size = sizeof(footer->cookie); 81 | if (memcmp(footer->cookie, HD_COOKIE, size)) 82 | return "invalid cookie"; 83 | 84 | checksum = vhd_checksum_footer(footer); 85 | if (checksum != footer->checksum) { 86 | if (footer->hidden && 87 | !strncmp(footer->crtr_app, "tap", 3) && 88 | (footer->crtr_ver == VHD_VERSION(0, 1) || 89 | footer->crtr_ver == VHD_VERSION(1, 1))) { 90 | char tmp = footer->hidden; 91 | footer->hidden = 0; 92 | checksum = vhd_checksum_footer(footer); 93 | footer->hidden = tmp; 94 | 95 | if (checksum == footer->checksum) 96 | goto ok; 97 | } 98 | 99 | return "invalid checksum"; 100 | } 101 | 102 | ok: 103 | if (!(footer->features & HD_RESERVED)) 104 | return "invalid 'reserved' feature"; 105 | 106 | if (footer->features & ~(HD_TEMPORARY | HD_RESERVED)) 107 | return "invalid extra features"; 108 | 109 | if (footer->ff_version != HD_FF_VERSION) 110 | return "invalid file format version"; 111 | 112 | if (footer->type != HD_TYPE_DYNAMIC && 113 | footer->type != HD_TYPE_DIFF && 114 | footer->data_offset != ~(0ULL)) 115 | return "invalid data offset"; 116 | 117 | now = vhd_time(time(NULL)); 118 | if (footer->timestamp > now + TIMESTAMP_MAX_SLACK) 119 | return "creation time in future"; 120 | 121 | if (!strncmp(footer->crtr_app, "tap", 3) && 122 | footer->crtr_ver > VHD_CURRENT_VERSION) 123 | return "unsupported tap creator version"; 124 | 125 | if (vhd_chs(footer->curr_size) < footer->geometry) 126 | return "geometry too large"; 127 | 128 | if (footer->type != HD_TYPE_FIXED && 129 | footer->type != HD_TYPE_DYNAMIC && 130 | footer->type != HD_TYPE_DIFF) 131 | return "invalid type"; 132 | 133 | if (footer->saved && footer->saved != 1) 134 | return "invalid 'saved' state"; 135 | 136 | if (footer->hidden && footer->hidden != 1) 137 | return "invalid 'hidden' state"; 138 | 139 | if (vhd_util_check_zeros(footer->reserved, 140 | sizeof(footer->reserved))) 141 | return "invalid 'reserved' bits"; 142 | 143 | return NULL; 144 | } 145 | 146 | static char * 147 | vhd_util_check_validate_header(int fd, vhd_header_t *header) 148 | { 149 | off_t eof; 150 | int i, cnt, size; 151 | uint32_t checksum; 152 | 153 | size = sizeof(header->cookie); 154 | if (memcmp(header->cookie, DD_COOKIE, size)) 155 | return "invalid cookie"; 156 | 157 | checksum = vhd_checksum_header(header); 158 | if (checksum != header->checksum) 159 | return "invalid checksum"; 160 | 161 | if (header->hdr_ver != 0x00010000) 162 | return "invalid header version"; 163 | 164 | if (header->data_offset != ~(0ULL)) 165 | return "invalid data offset"; 166 | 167 | eof = lseek(fd, 0, SEEK_END); 168 | if (eof == (off_t)-1) 169 | return "error finding eof"; 170 | 171 | if (header->table_offset <= 0 || 172 | header->table_offset % 512 || 173 | (header->table_offset + 174 | (header->max_bat_size * sizeof(uint32_t)) > 175 | eof - sizeof(vhd_footer_t))) 176 | return "invalid table offset"; 177 | 178 | for (cnt = 0, i = 0; i < sizeof(header->block_size) * 8; i++) 179 | if ((header->block_size >> i) & 1) 180 | cnt++; 181 | 182 | if (cnt != 1) 183 | return "invalid block size"; 184 | 185 | if (header->res1) 186 | return "invalid reserved bits"; 187 | 188 | if (vhd_util_check_zeros(header->res2, sizeof(header->res2))) 189 | return "invalid reserved bits"; 190 | 191 | return NULL; 192 | } 193 | 194 | static char * 195 | vhd_util_check_validate_differencing_header(vhd_context_t *vhd) 196 | { 197 | vhd_header_t *header; 198 | 199 | header = &vhd->header; 200 | 201 | if (vhd->footer.type == HD_TYPE_DIFF) { 202 | char *parent; 203 | uint32_t now; 204 | 205 | now = vhd_time(time(NULL)); 206 | if (header->prt_ts > now + TIMESTAMP_MAX_SLACK) 207 | return "parent creation time in future"; 208 | 209 | if (vhd_header_decode_parent(vhd, header, &parent)) 210 | return "invalid parent name"; 211 | 212 | free(parent); 213 | } else { 214 | if (vhd_util_check_zeros(header->prt_name, 215 | sizeof(header->prt_name))) 216 | return "invalid non-null parent name"; 217 | 218 | if (vhd_util_check_zeros(header->loc, sizeof(header->loc))) 219 | return "invalid non-null parent locators"; 220 | 221 | if (!vhd_uuid_is_nil(&header->prt_uuid)) 222 | return "invalid non-null parent uuid"; 223 | 224 | if (header->prt_ts) 225 | return "invalid non-zero parent timestamp"; 226 | } 227 | 228 | return NULL; 229 | } 230 | 231 | static char * 232 | vhd_util_check_validate_batmap(vhd_context_t *vhd, vhd_batmap_t *batmap) 233 | { 234 | int size; 235 | off_t eof; 236 | uint32_t checksum; 237 | 238 | size = sizeof(batmap->header.cookie); 239 | if (memcmp(batmap->header.cookie, VHD_BATMAP_COOKIE, size)) 240 | return "invalid cookie"; 241 | 242 | if (batmap->header.batmap_version > VHD_BATMAP_CURRENT_VERSION) 243 | return "unsupported batmap version"; 244 | 245 | checksum = vhd_checksum_batmap(batmap); 246 | if (checksum != batmap->header.checksum) 247 | return "invalid checksum"; 248 | 249 | if (!batmap->header.batmap_size) 250 | return "invalid size zero"; 251 | 252 | eof = lseek(vhd->fd, 0, SEEK_END); 253 | if (eof == (off_t)-1) 254 | return "error finding eof"; 255 | 256 | if (!batmap->header.batmap_offset || 257 | batmap->header.batmap_offset % 512) 258 | return "invalid batmap offset"; 259 | 260 | if ((batmap->header.batmap_offset + 261 | vhd_sectors_to_bytes(batmap->header.batmap_size)) > 262 | eof - sizeof(vhd_footer_t)) 263 | return "invalid batmap size"; 264 | 265 | return NULL; 266 | } 267 | 268 | static char * 269 | vhd_util_check_validate_parent_locator(vhd_context_t *vhd, 270 | vhd_parent_locator_t *loc) 271 | { 272 | off_t eof; 273 | 274 | if (vhd_validate_platform_code(loc->code)) 275 | return "invalid platform code"; 276 | 277 | if (loc->code == PLAT_CODE_NONE) { 278 | if (vhd_util_check_zeros(loc, sizeof(*loc))) 279 | return "non-zero locator"; 280 | 281 | return NULL; 282 | } 283 | 284 | if (!loc->data_offset) 285 | return "invalid data offset"; 286 | 287 | if (!loc->data_space) 288 | return "invalid data space"; 289 | 290 | if (!loc->data_len) 291 | return "invalid data length"; 292 | 293 | eof = lseek(vhd->fd, 0, SEEK_END); 294 | if (eof == (off_t)-1) 295 | return "error finding eof"; 296 | 297 | if (loc->data_offset + vhd_parent_locator_size(loc) > 298 | eof - sizeof(vhd_footer_t)) 299 | return "invalid size"; 300 | 301 | if (loc->res) 302 | return "invalid reserved bits"; 303 | 304 | return NULL; 305 | } 306 | 307 | static const char * 308 | vhd_util_check_validate_parent(vhd_context_t *vhd, const char *ppath) 309 | { 310 | const char *msg; 311 | vhd_context_t parent; 312 | uint32_t status; 313 | 314 | msg = NULL; 315 | 316 | if (vhd_parent_raw(vhd)) 317 | return msg; 318 | 319 | if (vhd_open(&parent, ppath, 320 | VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED)) 321 | return "error opening parent"; 322 | 323 | if (vhd_uuid_compare(&vhd->header.prt_uuid, &parent.footer.uuid)) { 324 | msg = "invalid parent uuid"; 325 | goto out; 326 | } 327 | 328 | out: 329 | vhd_close(&parent); 330 | return msg; 331 | } 332 | 333 | static int 334 | vhd_util_check_footer(int fd, vhd_footer_t *footer, int ignore) 335 | { 336 | size_t size; 337 | int err, opened; 338 | char *msg, *buf; 339 | off_t eof, off; 340 | vhd_footer_t primary, backup; 341 | 342 | memset(&primary, 0, sizeof(primary)); 343 | memset(&backup, 0, sizeof(backup)); 344 | 345 | err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(primary)); 346 | if (err) { 347 | printf("error allocating buffer: %d\n", err); 348 | return -err; 349 | } 350 | 351 | memset(buf, 0, sizeof(primary)); 352 | 353 | eof = lseek(fd, 0, SEEK_END); 354 | if (eof == (off_t)-1) { 355 | err = -errno; 356 | printf("error calculating end of file: %d\n", err); 357 | goto out; 358 | } 359 | 360 | size = ((eof % 512) ? 511 : 512); 361 | eof = lseek(fd, eof - size, SEEK_SET); 362 | if (eof == (off_t)-1) { 363 | err = -errno; 364 | printf("error calculating end of file: %d\n", err); 365 | goto out; 366 | } 367 | 368 | err = read(fd, buf, 512); 369 | if (err != size) { 370 | err = (errno ? -errno : -EIO); 371 | printf("error reading primary footer: %d\n", err); 372 | goto out; 373 | } 374 | 375 | memcpy(&primary, buf, sizeof(primary)); 376 | opened = vhd_util_check_footer_opened(&primary); 377 | vhd_footer_in(&primary); 378 | 379 | msg = vhd_util_check_validate_footer(&primary); 380 | if (msg) { 381 | if (opened && ignore) 382 | goto check_backup; 383 | 384 | err = -EINVAL; 385 | printf("primary footer invalid: %s\n", msg); 386 | goto out; 387 | } 388 | 389 | if (primary.type == HD_TYPE_FIXED) { 390 | err = 0; 391 | goto out; 392 | } 393 | 394 | check_backup: 395 | off = lseek(fd, 0, SEEK_SET); 396 | if (off == (off_t)-1) { 397 | err = -errno; 398 | printf("error seeking to backup footer: %d\n", err); 399 | goto out; 400 | } 401 | 402 | size = 512; 403 | memset(buf, 0, sizeof(primary)); 404 | 405 | err = read(fd, buf, size); 406 | if (err != size) { 407 | err = (errno ? -errno : -EIO); 408 | printf("error reading backup footer: %d\n", err); 409 | goto out; 410 | } 411 | 412 | memcpy(&backup, buf, sizeof(backup)); 413 | vhd_footer_in(&backup); 414 | 415 | msg = vhd_util_check_validate_footer(&backup); 416 | if (msg) { 417 | err = -EINVAL; 418 | printf("backup footer invalid: %s\n", msg); 419 | goto out; 420 | } 421 | 422 | if (memcmp(&primary, &backup, sizeof(primary))) { 423 | if (opened && ignore) { 424 | memcpy(&primary, &backup, sizeof(primary)); 425 | goto ok; 426 | } 427 | 428 | if (backup.hidden && 429 | !strncmp(backup.crtr_app, "tap", 3) && 430 | (backup.crtr_ver == VHD_VERSION(0, 1) || 431 | backup.crtr_ver == VHD_VERSION(1, 1))) { 432 | char cmp, tmp = backup.hidden; 433 | backup.hidden = 0; 434 | cmp = memcmp(&primary, &backup, sizeof(primary)); 435 | backup.hidden = tmp; 436 | if (!cmp) 437 | goto ok; 438 | } 439 | 440 | err = -EINVAL; 441 | printf("primary and backup footers do not match\n"); 442 | goto out; 443 | } 444 | 445 | ok: 446 | err = 0; 447 | memcpy(footer, &primary, sizeof(primary)); 448 | 449 | out: 450 | free(buf); 451 | return err; 452 | } 453 | 454 | static int 455 | vhd_util_check_header(int fd, vhd_footer_t *footer) 456 | { 457 | int err; 458 | off_t off; 459 | char *msg, *buf; 460 | vhd_header_t header; 461 | 462 | err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(header)); 463 | if (err) { 464 | printf("error allocating header: %d\n", err); 465 | return err; 466 | } 467 | 468 | off = footer->data_offset; 469 | off = lseek(fd, off, SEEK_SET); 470 | if (off == (off_t)-1) { 471 | err = -errno; 472 | printf("error seeking to header: %d\n", err); 473 | goto out; 474 | } 475 | 476 | err = read(fd, buf, sizeof(header)); 477 | if (err != sizeof(header)) { 478 | err = (errno ? -errno : -EIO); 479 | printf("error reading header: %d\n", err); 480 | goto out; 481 | } 482 | 483 | memcpy(&header, buf, sizeof(header)); 484 | vhd_header_in(&header); 485 | 486 | msg = vhd_util_check_validate_header(fd, &header); 487 | if (msg) { 488 | err = -EINVAL; 489 | printf("header is invalid: %s\n", msg); 490 | goto out; 491 | } 492 | 493 | err = 0; 494 | 495 | out: 496 | free(buf); 497 | return err; 498 | } 499 | 500 | static int 501 | vhd_util_check_differencing_header(vhd_context_t *vhd) 502 | { 503 | char *msg; 504 | 505 | msg = vhd_util_check_validate_differencing_header(vhd); 506 | if (msg) { 507 | printf("differencing header is invalid: %s\n", msg); 508 | return -EINVAL; 509 | } 510 | 511 | return 0; 512 | } 513 | 514 | static int 515 | vhd_util_check_bat(vhd_context_t *vhd) 516 | { 517 | off_t eof, eoh; 518 | int i, j, err, block_size; 519 | 520 | err = vhd_seek(vhd, 0, SEEK_END); 521 | if (err) { 522 | printf("error calculating eof: %d\n", err); 523 | return err; 524 | } 525 | 526 | eof = vhd_position(vhd); 527 | if (eof == (off_t)-1) { 528 | printf("error calculating eof: %d\n", -errno); 529 | return -errno; 530 | } 531 | 532 | /* adjust eof for vhds with short footers */ 533 | if (eof % 512) { 534 | if (eof % 512 != 511) { 535 | printf("invalid file size: 0x%"PRIx64"\n", eof); 536 | return -EINVAL; 537 | } 538 | 539 | eof++; 540 | } 541 | 542 | err = vhd_get_bat(vhd); 543 | if (err) { 544 | printf("error reading bat: %d\n", err); 545 | return err; 546 | } 547 | 548 | err = vhd_end_of_headers(vhd, &eoh); 549 | if (err) { 550 | printf("error calculating end of metadata: %d\n", err); 551 | return err; 552 | } 553 | 554 | eof -= sizeof(vhd_footer_t); 555 | eof >>= VHD_SECTOR_SHIFT; 556 | eoh >>= VHD_SECTOR_SHIFT; 557 | block_size = vhd->spb + vhd->bm_secs; 558 | 559 | for (i = 0; i < vhd->header.max_bat_size; i++) { 560 | uint32_t off = vhd->bat.bat[i]; 561 | if (off == DD_BLK_UNUSED) 562 | continue; 563 | 564 | if (off < eoh) { 565 | printf("block %d (offset 0x%x) clobbers headers\n", 566 | i, off); 567 | return -EINVAL; 568 | } 569 | 570 | if (off + block_size > eof) { 571 | printf("block %d (offset 0x%x) clobbers footer\n", 572 | i, off); 573 | return -EINVAL; 574 | } 575 | 576 | for (j = 0; j < vhd->header.max_bat_size; j++) { 577 | uint32_t joff = vhd->bat.bat[j]; 578 | 579 | if (i == j) 580 | continue; 581 | 582 | if (joff == DD_BLK_UNUSED) 583 | continue; 584 | 585 | if (off == joff) 586 | err = -EINVAL; 587 | 588 | if (off > joff && off < joff + block_size) 589 | err = -EINVAL; 590 | 591 | if (off + block_size > joff && 592 | off + block_size < joff + block_size) 593 | err = -EINVAL; 594 | 595 | if (err) { 596 | printf("block %d (offset 0x%x) clobbers " 597 | "block %d (offset 0x%x)\n", 598 | i, off, j, joff); 599 | return err; 600 | } 601 | } 602 | } 603 | 604 | return 0; 605 | } 606 | 607 | static int 608 | vhd_util_check_batmap(vhd_context_t *vhd) 609 | { 610 | char *msg; 611 | int i, err; 612 | 613 | err = vhd_get_bat(vhd); 614 | if (err) { 615 | printf("error reading bat: %d\n", err); 616 | return err; 617 | } 618 | 619 | err = vhd_get_batmap(vhd); 620 | if (err) { 621 | printf("error reading batmap: %d\n", err); 622 | return err; 623 | } 624 | 625 | msg = vhd_util_check_validate_batmap(vhd, &vhd->batmap); 626 | if (msg) { 627 | printf("batmap is invalid: %s\n", msg); 628 | return -EINVAL; 629 | } 630 | 631 | for (i = 0; i < vhd->header.max_bat_size; i++) { 632 | if (!vhd_batmap_test(vhd, &vhd->batmap, i)) 633 | continue; 634 | 635 | if (vhd->bat.bat[i] == DD_BLK_UNUSED) { 636 | printf("batmap shows unallocated block %d full\n", i); 637 | return -EINVAL; 638 | } 639 | } 640 | 641 | return 0; 642 | } 643 | 644 | static int 645 | vhd_util_check_parent_locators(vhd_context_t *vhd) 646 | { 647 | int i, n, err; 648 | vhd_parent_locator_t *loc; 649 | char *file, *ppath, *location, *pname; 650 | const char *msg; 651 | int mac, macx, w2ku, w2ru, wi2r, wi2k, found; 652 | 653 | mac = 0; 654 | macx = 0; 655 | w2ku = 0; 656 | w2ru = 0; 657 | wi2r = 0; 658 | wi2k = 0; 659 | found = 0; 660 | pname = NULL; 661 | ppath = NULL; 662 | location = NULL; 663 | 664 | err = vhd_header_decode_parent(vhd, &vhd->header, &pname); 665 | if (err) { 666 | printf("error decoding parent name: %d\n", err); 667 | return err; 668 | } 669 | 670 | n = sizeof(vhd->header.loc) / sizeof(vhd->header.loc[0]); 671 | for (i = 0; i < n; i++) { 672 | ppath = NULL; 673 | location = NULL; 674 | loc = vhd->header.loc + i; 675 | 676 | msg = vhd_util_check_validate_parent_locator(vhd, loc); 677 | if (msg) { 678 | err = -EINVAL; 679 | printf("invalid parent locator %d: %s\n", i, msg); 680 | goto out; 681 | } 682 | 683 | if (loc->code == PLAT_CODE_NONE) 684 | continue; 685 | 686 | switch (loc->code) { 687 | case PLAT_CODE_MACX: 688 | if (macx++) 689 | goto dup; 690 | break; 691 | 692 | case PLAT_CODE_MAC: 693 | if (mac++) 694 | goto dup; 695 | break; 696 | 697 | case PLAT_CODE_W2KU: 698 | if (w2ku++) 699 | goto dup; 700 | break; 701 | 702 | case PLAT_CODE_W2RU: 703 | if (w2ru++) 704 | goto dup; 705 | break; 706 | 707 | case PLAT_CODE_WI2R: 708 | if (wi2r++) 709 | goto dup; 710 | break; 711 | 712 | case PLAT_CODE_WI2K: 713 | if (wi2k++) 714 | goto dup; 715 | break; 716 | 717 | default: 718 | err = -EINVAL; 719 | printf("invalid platform code for locator %d\n", i); 720 | goto out; 721 | } 722 | 723 | if (loc->code != PLAT_CODE_MACX && 724 | loc->code != PLAT_CODE_W2RU && 725 | loc->code != PLAT_CODE_W2KU) 726 | continue; 727 | 728 | err = vhd_parent_locator_read(vhd, loc, &ppath); 729 | if (err) { 730 | printf("error reading parent locator %d: %d\n", i, err); 731 | goto out; 732 | } 733 | 734 | file = basename(ppath); 735 | if (strcmp(pname, file)) { 736 | err = -EINVAL; 737 | printf("parent locator %d name (%s) does not match " 738 | "header name (%s)\n", i, file, pname); 739 | goto out; 740 | } 741 | 742 | err = vhd_find_parent(vhd, ppath, &location); 743 | if (err) { 744 | printf("error resolving %s: %d\n", ppath, err); 745 | goto out; 746 | } 747 | 748 | err = access(location, R_OK); 749 | if (err && loc->code == PLAT_CODE_MACX) { 750 | err = -errno; 751 | printf("parent locator %d points to missing file %s " 752 | "(resolved to %s)\n", i, ppath, location); 753 | goto out; 754 | } 755 | 756 | msg = vhd_util_check_validate_parent(vhd, location); 757 | if (msg) { 758 | err = -EINVAL; 759 | printf("invalid parent %s: %s\n", location, msg); 760 | goto out; 761 | } 762 | 763 | found++; 764 | free(ppath); 765 | free(location); 766 | ppath = NULL; 767 | location = NULL; 768 | 769 | continue; 770 | 771 | dup: 772 | printf("duplicate platform code in locator %d: 0x%x\n", 773 | i, loc->code); 774 | err = -EINVAL; 775 | goto out; 776 | } 777 | 778 | if (!found) { 779 | err = -EINVAL; 780 | printf("could not find parent %s\n", pname); 781 | goto out; 782 | } 783 | 784 | err = 0; 785 | 786 | out: 787 | free(pname); 788 | free(ppath); 789 | free(location); 790 | return err; 791 | } 792 | 793 | static void 794 | vhd_util_dump_headers(const char *name) 795 | { 796 | char *argv[] = { "read", "-p", "-n", (char *)name }; 797 | int argc = sizeof(argv) / sizeof(argv[0]); 798 | 799 | printf("%s appears invalid; dumping metadata\n", name); 800 | vhd_util_read(argc, argv); 801 | } 802 | 803 | static int 804 | vhd_util_check_vhd(const char *name, int ignore) 805 | { 806 | int fd, err; 807 | vhd_context_t vhd; 808 | struct stat stats; 809 | vhd_footer_t footer; 810 | 811 | fd = -1; 812 | memset(&vhd, 0, sizeof(vhd)); 813 | memset(&footer, 0, sizeof(footer)); 814 | 815 | err = stat(name, &stats); 816 | if (err == -1) { 817 | printf("cannot stat %s: %d\n", name, errno); 818 | return -errno; 819 | } 820 | 821 | if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) { 822 | printf("%s is not a regular file or block device\n", name); 823 | return -EINVAL; 824 | } 825 | 826 | fd = open(name, O_RDONLY | O_DIRECT | O_LARGEFILE); 827 | if (fd == -1) { 828 | printf("error opening %s\n", name); 829 | return -errno; 830 | } 831 | 832 | err = vhd_util_check_footer(fd, &footer, ignore); 833 | if (err) 834 | goto out; 835 | 836 | if (footer.type != HD_TYPE_DYNAMIC && footer.type != HD_TYPE_DIFF) 837 | goto out; 838 | 839 | err = vhd_util_check_header(fd, &footer); 840 | if (err) 841 | goto out; 842 | 843 | err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED); 844 | if (err) 845 | goto out; 846 | 847 | err = vhd_util_check_differencing_header(&vhd); 848 | if (err) 849 | goto out; 850 | 851 | err = vhd_util_check_bat(&vhd); 852 | if (err) 853 | goto out; 854 | 855 | if (vhd_has_batmap(&vhd)) { 856 | err = vhd_util_check_batmap(&vhd); 857 | if (err) 858 | goto out; 859 | } 860 | 861 | if (vhd.footer.type == HD_TYPE_DIFF) { 862 | err = vhd_util_check_parent_locators(&vhd); 863 | if (err) 864 | goto out; 865 | } 866 | 867 | err = 0; 868 | printf("%s is valid\n", name); 869 | 870 | out: 871 | if (err) 872 | vhd_util_dump_headers(name); 873 | if (fd != -1) 874 | close(fd); 875 | vhd_close(&vhd); 876 | return err; 877 | } 878 | 879 | static int 880 | vhd_util_check_parents(const char *name, int ignore) 881 | { 882 | int err; 883 | vhd_context_t vhd; 884 | char *cur, *parent; 885 | 886 | cur = (char *)name; 887 | 888 | for (;;) { 889 | err = vhd_open(&vhd, cur, 890 | VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED); 891 | if (err) 892 | goto out; 893 | 894 | if (vhd.footer.type != HD_TYPE_DIFF || vhd_parent_raw(&vhd)) { 895 | vhd_close(&vhd); 896 | goto out; 897 | } 898 | 899 | err = vhd_parent_locator_get(&vhd, &parent); 900 | vhd_close(&vhd); 901 | 902 | if (err) { 903 | printf("error getting parent: %d\n", err); 904 | goto out; 905 | } 906 | 907 | if (cur != name) 908 | free(cur); 909 | cur = parent; 910 | 911 | err = vhd_util_check_vhd(cur, ignore); 912 | if (err) 913 | goto out; 914 | } 915 | 916 | out: 917 | if (err) 918 | printf("error checking parents: %d\n", err); 919 | if (cur != name) 920 | free(cur); 921 | return err; 922 | } 923 | 924 | int 925 | vhd_util_check(int argc, char **argv) 926 | { 927 | char *name; 928 | vhd_context_t vhd; 929 | int c, err, ignore, parents; 930 | 931 | if (!argc || !argv) { 932 | err = -EINVAL; 933 | goto usage; 934 | } 935 | 936 | ignore = 0; 937 | parents = 0; 938 | name = NULL; 939 | 940 | optind = 0; 941 | while ((c = getopt(argc, argv, "n:iph")) != -1) { 942 | switch (c) { 943 | case 'n': 944 | name = optarg; 945 | break; 946 | case 'i': 947 | ignore = 1; 948 | break; 949 | case 'p': 950 | parents = 1; 951 | break; 952 | case 'h': 953 | err = 0; 954 | goto usage; 955 | default: 956 | err = -EINVAL; 957 | goto usage; 958 | } 959 | } 960 | 961 | if (!name || optind != argc) { 962 | err = -EINVAL; 963 | goto usage; 964 | } 965 | 966 | err = vhd_util_check_vhd(name, ignore); 967 | if (err) 968 | goto out; 969 | 970 | if (parents) 971 | err = vhd_util_check_parents(name, ignore); 972 | 973 | out: 974 | return err; 975 | 976 | usage: 977 | printf("options: -n [-i ignore missing primary footers] " 978 | "[-p check parents] [-h help]\n"); 979 | return err; 980 | } 981 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-coalesce.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "libvhd.h" 34 | 35 | static int 36 | __raw_io_write(int fd, char* buf, uint64_t sec, uint32_t secs) 37 | { 38 | off_t off; 39 | size_t ret; 40 | 41 | errno = 0; 42 | off = lseek(fd, vhd_sectors_to_bytes(sec), SEEK_SET); 43 | if (off == (off_t)-1) { 44 | printf("raw parent: seek(0x%08"PRIx64") failed: %d\n", 45 | vhd_sectors_to_bytes(sec), -errno); 46 | return -errno; 47 | } 48 | 49 | ret = write(fd, buf, vhd_sectors_to_bytes(secs)); 50 | if (ret == vhd_sectors_to_bytes(secs)) 51 | return 0; 52 | 53 | printf("raw parent: write of 0x%"PRIx64" returned %zd, errno: %d\n", 54 | vhd_sectors_to_bytes(secs), ret, -errno); 55 | return (errno ? -errno : -EIO); 56 | } 57 | 58 | /* 59 | * Use 'parent' if the parent is VHD, and 'parent_fd' if the parent is raw 60 | */ 61 | static int 62 | vhd_util_coalesce_block(vhd_context_t *vhd, vhd_context_t *parent, 63 | int parent_fd, uint64_t block) 64 | { 65 | int i, err; 66 | char *buf, *map; 67 | uint64_t sec, secs; 68 | 69 | buf = NULL; 70 | map = NULL; 71 | sec = block * vhd->spb; 72 | 73 | if (vhd->bat.bat[block] == DD_BLK_UNUSED) 74 | return 0; 75 | 76 | err = posix_memalign((void **)&buf, 4096, vhd->header.block_size); 77 | if (err) 78 | return -err; 79 | 80 | err = vhd_io_read(vhd, buf, sec, vhd->spb); 81 | if (err) 82 | goto done; 83 | 84 | if (vhd_has_batmap(vhd) && vhd_batmap_test(vhd, &vhd->batmap, block)) { 85 | if (parent->file) 86 | err = vhd_io_write(parent, buf, sec, vhd->spb); 87 | else 88 | err = __raw_io_write(parent_fd, buf, sec, vhd->spb); 89 | goto done; 90 | } 91 | 92 | err = vhd_read_bitmap(vhd, block, &map); 93 | if (err) 94 | goto done; 95 | 96 | for (i = 0; i < vhd->spb; i++) { 97 | if (!vhd_bitmap_test(vhd, map, i)) 98 | continue; 99 | 100 | for (secs = 0; i + secs < vhd->spb; secs++) 101 | if (!vhd_bitmap_test(vhd, map, i + secs)) 102 | break; 103 | 104 | if (parent->file) 105 | err = vhd_io_write(parent, 106 | buf + vhd_sectors_to_bytes(i), 107 | sec + i, secs); 108 | else 109 | err = __raw_io_write(parent_fd, 110 | buf + vhd_sectors_to_bytes(i), 111 | sec + i, secs); 112 | if (err) 113 | goto done; 114 | 115 | i += secs; 116 | } 117 | 118 | err = 0; 119 | 120 | done: 121 | free(buf); 122 | free(map); 123 | return err; 124 | } 125 | 126 | int 127 | vhd_util_coalesce(int argc, char **argv) 128 | { 129 | int err, c; 130 | uint64_t i; 131 | char *name, *pname; 132 | vhd_context_t vhd, parent; 133 | int parent_fd = -1; 134 | 135 | name = NULL; 136 | pname = NULL; 137 | parent.file = NULL; 138 | 139 | if (!argc || !argv) 140 | goto usage; 141 | 142 | optind = 0; 143 | while ((c = getopt(argc, argv, "n:h")) != -1) { 144 | switch (c) { 145 | case 'n': 146 | name = optarg; 147 | break; 148 | case 'h': 149 | default: 150 | goto usage; 151 | } 152 | } 153 | 154 | if (!name || optind != argc) 155 | goto usage; 156 | 157 | err = vhd_open(&vhd, name, VHD_OPEN_RDONLY); 158 | if (err) { 159 | printf("error opening %s: %d\n", name, err); 160 | return err; 161 | } 162 | 163 | err = vhd_parent_locator_get(&vhd, &pname); 164 | if (err) { 165 | printf("error finding %s parent: %d\n", name, err); 166 | vhd_close(&vhd); 167 | return err; 168 | } 169 | 170 | if (vhd_parent_raw(&vhd)) { 171 | parent_fd = open(pname, O_RDWR | O_DIRECT | O_LARGEFILE, 0644); 172 | if (parent_fd == -1) { 173 | err = -errno; 174 | printf("failed to open parent %s: %d\n", pname, err); 175 | vhd_close(&vhd); 176 | return err; 177 | } 178 | } else { 179 | err = vhd_open(&parent, pname, VHD_OPEN_RDWR); 180 | if (err) { 181 | printf("error opening %s: %d\n", pname, err); 182 | free(pname); 183 | vhd_close(&vhd); 184 | return err; 185 | } 186 | } 187 | 188 | err = vhd_get_bat(&vhd); 189 | if (err) 190 | goto done; 191 | 192 | if (vhd_has_batmap(&vhd)) { 193 | err = vhd_get_batmap(&vhd); 194 | if (err) 195 | goto done; 196 | } 197 | 198 | for (i = 0; i < vhd.bat.entries; i++) { 199 | err = vhd_util_coalesce_block(&vhd, &parent, parent_fd, i); 200 | if (err) 201 | goto done; 202 | } 203 | 204 | err = 0; 205 | 206 | done: 207 | free(pname); 208 | vhd_close(&vhd); 209 | if (parent.file) 210 | vhd_close(&parent); 211 | else 212 | close(parent_fd); 213 | return err; 214 | 215 | usage: 216 | printf("options: <-n name> [-h help]\n"); 217 | return -EINVAL; 218 | } 219 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-create.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "libvhd.h" 33 | 34 | int 35 | vhd_util_create(int argc, char **argv) 36 | { 37 | char *name; 38 | uint64_t size; 39 | int c, sparse, err; 40 | vhd_flag_creat_t flags; 41 | 42 | err = -EINVAL; 43 | size = 0; 44 | sparse = 1; 45 | name = NULL; 46 | flags = 0; 47 | 48 | if (!argc || !argv) 49 | goto usage; 50 | 51 | optind = 0; 52 | while ((c = getopt(argc, argv, "n:s:rh")) != -1) { 53 | switch (c) { 54 | case 'n': 55 | name = optarg; 56 | break; 57 | case 's': 58 | err = 0; 59 | size = strtoull(optarg, NULL, 10); 60 | break; 61 | case 'r': 62 | sparse = 0; 63 | break; 64 | case 'h': 65 | default: 66 | goto usage; 67 | } 68 | } 69 | 70 | if (err || !name || optind != argc) 71 | goto usage; 72 | 73 | return vhd_create(name, size << 20, 74 | (sparse ? HD_TYPE_DYNAMIC : HD_TYPE_FIXED), 75 | flags); 76 | 77 | usage: 78 | printf("options: <-n name> <-s size (MB)> [-r reserve] [-h help]\n"); 79 | return -EINVAL; 80 | } 81 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-fill.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "libvhd.h" 34 | 35 | int 36 | vhd_util_fill(int argc, char **argv) 37 | { 38 | int err, c; 39 | char *buf, *name; 40 | vhd_context_t vhd; 41 | uint64_t i, sec, secs; 42 | 43 | buf = NULL; 44 | name = NULL; 45 | 46 | if (!argc || !argv) 47 | goto usage; 48 | 49 | optind = 0; 50 | while ((c = getopt(argc, argv, "n:h")) != -1) { 51 | switch (c) { 52 | case 'n': 53 | name = optarg; 54 | break; 55 | case 'h': 56 | default: 57 | goto usage; 58 | } 59 | } 60 | 61 | if (!name || optind != argc) 62 | goto usage; 63 | 64 | err = vhd_open(&vhd, name, VHD_OPEN_RDWR); 65 | if (err) { 66 | printf("error opening %s: %d\n", name, err); 67 | return err; 68 | } 69 | 70 | err = vhd_get_bat(&vhd); 71 | if (err) 72 | goto done; 73 | 74 | err = posix_memalign((void **)&buf, 4096, vhd.header.block_size); 75 | if (err) { 76 | err = -err; 77 | goto done; 78 | } 79 | 80 | sec = 0; 81 | secs = vhd.header.block_size >> VHD_SECTOR_SHIFT; 82 | 83 | for (i = 0; i < vhd.header.max_bat_size; i++) { 84 | err = vhd_io_read(&vhd, buf, sec, secs); 85 | if (err) 86 | goto done; 87 | 88 | err = vhd_io_write(&vhd, buf, sec, secs); 89 | if (err) 90 | goto done; 91 | 92 | sec += secs; 93 | } 94 | 95 | err = 0; 96 | 97 | done: 98 | free(buf); 99 | vhd_close(&vhd); 100 | return err; 101 | 102 | usage: 103 | printf("options: <-n name> [-h help]\n"); 104 | return -EINVAL; 105 | } 106 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-modify.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | * Altering operations: 28 | * 29 | * 1. Change the parent pointer to another file. 30 | * 2. Change the size of the file containing the VHD image. This does NOT 31 | * affect the VHD disk capacity, only the physical size of the file containing 32 | * the VHD. Naturally, it is not possible to set the file size to be less than 33 | * the what VHD utilizes. 34 | * The operation doesn't actually change the file size, but it writes the 35 | * footer in the right location such that resizing the file (manually, as a 36 | * separate step) will produce the correct results. If the new file size is 37 | * greater than the current file size, the file must first be expanded and then 38 | * altered with this operation. If the new size is smaller than the current 39 | * size, the VHD must first be altered with this operation and then the file 40 | * must be shrunk. Failing to resize the file will result in a corrupted VHD. 41 | */ 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "libvhd.h" 50 | 51 | TEST_FAIL_EXTERN_VARS; 52 | 53 | int 54 | vhd_util_modify(int argc, char **argv) 55 | { 56 | char *name; 57 | vhd_context_t vhd; 58 | int err, c, size, parent, parent_raw; 59 | off_t newsize = 0; 60 | char *newparent = NULL; 61 | 62 | name = NULL; 63 | size = 0; 64 | parent = 0; 65 | parent_raw = 0; 66 | 67 | optind = 0; 68 | while ((c = getopt(argc, argv, "n:s:p:mh")) != -1) { 69 | switch (c) { 70 | case 'n': 71 | name = optarg; 72 | break; 73 | case 's': 74 | size = 1; 75 | errno = 0; 76 | newsize = strtoll(optarg, NULL, 10); 77 | if (errno) { 78 | fprintf(stderr, "Invalid size '%s'\n", optarg); 79 | goto usage; 80 | } 81 | break; 82 | case 'p': 83 | parent = 1; 84 | newparent = optarg; 85 | break; 86 | case 'm': 87 | parent_raw = 1; 88 | break; 89 | 90 | case 'h': 91 | default: 92 | goto usage; 93 | } 94 | } 95 | 96 | if (!name || optind != argc) 97 | goto usage; 98 | 99 | err = vhd_open(&vhd, name, VHD_OPEN_RDWR); 100 | if (err) { 101 | printf("error opening %s: %d\n", name, err); 102 | return err; 103 | } 104 | 105 | if (size) { 106 | err = vhd_set_phys_size(&vhd, newsize); 107 | if (err) 108 | printf("failed to set physical size to %"PRIu64":" 109 | " %d\n", newsize, err); 110 | } 111 | 112 | if (parent) { 113 | TEST_FAIL_AT(FAIL_REPARENT_BEGIN); 114 | err = vhd_change_parent(&vhd, newparent, parent_raw); 115 | if (err) { 116 | printf("failed to set parent to '%s': %d\n", 117 | newparent, err); 118 | goto done; 119 | } 120 | TEST_FAIL_AT(FAIL_REPARENT_END); 121 | } 122 | 123 | done: 124 | vhd_close(&vhd); 125 | return err; 126 | 127 | usage: 128 | printf("*** Dangerous operations, use with care ***\n"); 129 | printf("options: <-n name> [-p NEW_PARENT set parent [-m raw]] " 130 | "[-s NEW_SIZE set size] [-h help]\n"); 131 | return -EINVAL; 132 | } 133 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-query.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "libvhd.h" 34 | 35 | int 36 | vhd_util_query(int argc, char **argv) 37 | { 38 | char *name; 39 | vhd_context_t vhd; 40 | off_t currsize; 41 | int ret, err, c, size, physize, parent, fields, depth; 42 | 43 | name = NULL; 44 | size = 0; 45 | physize = 0; 46 | parent = 0; 47 | fields = 0; 48 | depth = 0; 49 | 50 | if (!argc || !argv) { 51 | err = -EINVAL; 52 | goto usage; 53 | } 54 | 55 | optind = 0; 56 | while ((c = getopt(argc, argv, "n:vspfdh")) != -1) { 57 | switch (c) { 58 | case 'n': 59 | name = optarg; 60 | break; 61 | case 'v': 62 | size = 1; 63 | break; 64 | case 's': 65 | physize = 1; 66 | break; 67 | case 'p': 68 | parent = 1; 69 | break; 70 | case 'f': 71 | fields = 1; 72 | break; 73 | case 'd': 74 | depth = 1; 75 | break; 76 | case 'h': 77 | err = 0; 78 | goto usage; 79 | default: 80 | err = -EINVAL; 81 | goto usage; 82 | } 83 | } 84 | 85 | if (!name || optind != argc) { 86 | err = -EINVAL; 87 | goto usage; 88 | } 89 | 90 | err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED); 91 | if (err) { 92 | printf("error opening %s: %d\n", name, err); 93 | return err; 94 | } 95 | 96 | if (size) 97 | printf("%"PRIu64"\n", vhd.footer.curr_size >> 20); 98 | 99 | if (physize) { 100 | err = vhd_get_phys_size(&vhd, &currsize); 101 | if (err) 102 | printf("failed to get physical size: %d\n", err); 103 | else 104 | printf("%"PRIu64"\n", currsize); 105 | } 106 | 107 | if (parent) { 108 | ret = 0; 109 | 110 | if (vhd.footer.type != HD_TYPE_DIFF) 111 | printf("%s has no parent\n", name); 112 | else { 113 | char *pname; 114 | 115 | ret = vhd_parent_locator_get(&vhd, &pname); 116 | if (ret) 117 | printf("query failed\n"); 118 | else { 119 | printf("%s\n", pname); 120 | free(pname); 121 | } 122 | } 123 | 124 | err = (err ? : ret); 125 | } 126 | 127 | if (fields) { 128 | int hidden; 129 | 130 | ret = vhd_hidden(&vhd, &hidden); 131 | if (ret) 132 | printf("error checking 'hidden' field: %d\n", ret); 133 | else 134 | printf("hidden: %d\n", hidden); 135 | 136 | err = (err ? : ret); 137 | } 138 | 139 | if (depth) { 140 | int length; 141 | 142 | ret = vhd_chain_depth(&vhd, &length); 143 | if (ret) 144 | printf("error checking chain depth: %d\n", ret); 145 | else 146 | printf("chain depth: %d\n", length); 147 | 148 | err = (err ? : ret); 149 | } 150 | 151 | vhd_close(&vhd); 152 | return err; 153 | 154 | usage: 155 | printf("options: <-n name> [-v print virtual size (in MB)] " 156 | "[-s print physical utilization (bytes)] [-p print parent] " 157 | "[-f print fields] [-d print chain depth] [-h help]\n"); 158 | return err; 159 | } 160 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-read.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "libvhd.h" 35 | #include "vhd-util.h" 36 | 37 | #define nsize 15 38 | static char nbuf[nsize]; 39 | 40 | static inline char * 41 | __xconv(uint64_t num) 42 | { 43 | snprintf(nbuf, nsize, "%#" PRIx64 , num); 44 | return nbuf; 45 | } 46 | 47 | static inline char * 48 | __dconv(uint64_t num) 49 | { 50 | snprintf(nbuf, nsize, "%" PRIu64, num); 51 | return nbuf; 52 | } 53 | 54 | #define conv(hex, num) \ 55 | (hex ? __xconv((uint64_t)num) : __dconv((uint64_t)num)) 56 | 57 | static void 58 | vhd_print_header(vhd_context_t *vhd, vhd_header_t *h, int hex) 59 | { 60 | int err; 61 | uint32_t cksm; 62 | char uuid[39], time_str[26], cookie[9], out[512], *name; 63 | 64 | printf("VHD Header Summary:\n-------------------\n"); 65 | 66 | snprintf(cookie, sizeof(cookie), "%s", h->cookie); 67 | printf("Cookie : %s\n", cookie); 68 | 69 | printf("Data offset (unusd) : %s\n", conv(hex, h->data_offset)); 70 | printf("Table offset : %s\n", conv(hex, h->table_offset)); 71 | printf("Header version : 0x%08x\n", h->hdr_ver); 72 | printf("Max BAT size : %s\n", conv(hex, h->max_bat_size)); 73 | printf("Block size : %s ", conv(hex, h->block_size)); 74 | printf("(%s MB)\n", conv(hex, h->block_size >> 20)); 75 | 76 | err = vhd_header_decode_parent(vhd, h, &name); 77 | printf("Parent name : %s\n", 78 | (err ? "failed to read name" : name)); 79 | free(name); 80 | 81 | vhd_uuid_to_string(&h->prt_uuid, uuid, sizeof(uuid)); 82 | printf("Parent UUID : %s\n", uuid); 83 | 84 | vhd_time_to_string(h->prt_ts, time_str); 85 | printf("Parent timestamp : %s\n", time_str); 86 | 87 | cksm = vhd_checksum_header(h); 88 | printf("Checksum : 0x%x|0x%x (%s)\n", h->checksum, cksm, 89 | h->checksum == cksm ? "Good!" : "Bad!"); 90 | printf("\n"); 91 | } 92 | 93 | static void 94 | vhd_print_footer(vhd_footer_t *f, int hex) 95 | { 96 | uint64_t c, h, s; 97 | uint32_t ff_maj, ff_min, cr_maj, cr_min, cksm, cksm_save; 98 | char time_str[26], creator[5], uuid[39], cookie[9]; 99 | 100 | printf("VHD Footer Summary:\n-------------------\n"); 101 | 102 | snprintf(cookie, sizeof(cookie), "%s", f->cookie); 103 | printf("Cookie : %s\n", cookie); 104 | 105 | printf("Features : (0x%08x) %s%s\n", f->features, 106 | (f->features & HD_TEMPORARY) ? "" : "", 107 | (f->features & HD_RESERVED) ? "" : ""); 108 | 109 | ff_maj = f->ff_version >> 16; 110 | ff_min = f->ff_version & 0xffff; 111 | printf("File format version : Major: %d, Minor: %d\n", 112 | ff_maj, ff_min); 113 | 114 | printf("Data offset : %s\n", conv(hex, f->data_offset)); 115 | 116 | vhd_time_to_string(f->timestamp, time_str); 117 | printf("Timestamp : %s\n", time_str); 118 | 119 | memcpy(creator, f->crtr_app, 4); 120 | creator[4] = '\0'; 121 | printf("Creator Application : '%s'\n", creator); 122 | 123 | cr_maj = f->crtr_ver >> 16; 124 | cr_min = f->crtr_ver & 0xffff; 125 | printf("Creator version : Major: %d, Minor: %d\n", 126 | cr_maj, cr_min); 127 | 128 | printf("Creator OS : %s\n", 129 | ((f->crtr_os == HD_CR_OS_WINDOWS) ? "Windows" : 130 | ((f->crtr_os == HD_CR_OS_MACINTOSH) ? "Macintosh" : 131 | "Unknown!"))); 132 | 133 | printf("Original disk size : %s MB ", conv(hex, f->orig_size >> 20)); 134 | printf("(%s Bytes)\n", conv(hex, f->orig_size)); 135 | 136 | printf("Current disk size : %s MB ", conv(hex, f->curr_size >> 20)); 137 | printf("(%s Bytes)\n", conv(hex, f->curr_size)); 138 | 139 | c = f->geometry >> 16; 140 | h = (f->geometry & 0x0000FF00) >> 8; 141 | s = f->geometry & 0x000000FF; 142 | printf("Geometry : Cyl: %s, ", conv(hex, c)); 143 | printf("Hds: %s, ", conv(hex, h)); 144 | printf("Sctrs: %s\n", conv(hex, s)); 145 | printf(" : = %s MB ", conv(hex, (c * h * s) >> 11)); 146 | printf("(%s Bytes)\n", conv(hex, c * h * s << 9)); 147 | 148 | printf("Disk type : %s\n", 149 | f->type <= HD_TYPE_MAX ? 150 | HD_TYPE_STR[f->type] : "Unknown type!\n"); 151 | 152 | cksm = vhd_checksum_footer(f); 153 | printf("Checksum : 0x%x|0x%x (%s)\n", f->checksum, cksm, 154 | f->checksum == cksm ? "Good!" : "Bad!"); 155 | 156 | vhd_uuid_to_string(&f->uuid, uuid, sizeof(uuid)); 157 | printf("UUID : %s\n", uuid); 158 | 159 | printf("Saved state : %s\n", f->saved == 0 ? "No" : "Yes"); 160 | printf("Hidden : %d\n", f->hidden); 161 | printf("\n"); 162 | } 163 | 164 | static inline char * 165 | code_name(uint32_t code) 166 | { 167 | switch(code) { 168 | case PLAT_CODE_NONE: 169 | return "PLAT_CODE_NONE"; 170 | case PLAT_CODE_WI2R: 171 | return "PLAT_CODE_WI2R"; 172 | case PLAT_CODE_WI2K: 173 | return "PLAT_CODE_WI2K"; 174 | case PLAT_CODE_W2RU: 175 | return "PLAT_CODE_W2RU"; 176 | case PLAT_CODE_W2KU: 177 | return "PLAT_CODE_W2KU"; 178 | case PLAT_CODE_MAC: 179 | return "PLAT_CODE_MAC"; 180 | case PLAT_CODE_MACX: 181 | return "PLAT_CODE_MACX"; 182 | default: 183 | return "UNKOWN"; 184 | } 185 | } 186 | 187 | static void 188 | vhd_print_parent(vhd_context_t *vhd, vhd_parent_locator_t *loc) 189 | { 190 | int err; 191 | char *buf; 192 | 193 | err = vhd_parent_locator_read(vhd, loc, &buf); 194 | if (err) { 195 | printf("failed to read parent name\n"); 196 | return; 197 | } 198 | 199 | printf(" decoded name : %s\n", buf); 200 | } 201 | 202 | static void 203 | vhd_print_parent_locators(vhd_context_t *vhd, int hex) 204 | { 205 | int i, n; 206 | vhd_parent_locator_t *loc; 207 | 208 | printf("VHD Parent Locators:\n--------------------\n"); 209 | 210 | n = sizeof(vhd->header.loc) / sizeof(struct prt_loc); 211 | for (i = 0; i < n; i++) { 212 | loc = &vhd->header.loc[i]; 213 | 214 | if (loc->code == PLAT_CODE_NONE) 215 | continue; 216 | 217 | printf("locator: : %d\n", i); 218 | printf(" code : %s\n", 219 | code_name(loc->code)); 220 | printf(" data_space : %s\n", 221 | conv(hex, loc->data_space)); 222 | printf(" data_length : %s\n", 223 | conv(hex, loc->data_len)); 224 | printf(" data_offset : %s\n", 225 | conv(hex, loc->data_offset)); 226 | vhd_print_parent(vhd, loc); 227 | printf("\n"); 228 | } 229 | } 230 | 231 | static void 232 | vhd_print_batmap_header(vhd_batmap_t *batmap, int hex) 233 | { 234 | uint32_t cksm; 235 | 236 | printf("VHD Batmap Summary:\n-------------------\n"); 237 | printf("Batmap offset : %s\n", 238 | conv(hex, batmap->header.batmap_offset)); 239 | printf("Batmap size (secs) : %s\n", 240 | conv(hex, batmap->header.batmap_size)); 241 | printf("Batmap version : 0x%08x\n", 242 | batmap->header.batmap_version); 243 | 244 | cksm = vhd_checksum_batmap(batmap); 245 | printf("Checksum : 0x%x|0x%x (%s)\n", 246 | batmap->header.checksum, cksm, 247 | (batmap->header.checksum == cksm ? "Good!" : "Bad!")); 248 | printf("\n"); 249 | } 250 | 251 | static inline int 252 | check_block_range(vhd_context_t *vhd, uint64_t block, int hex) 253 | { 254 | if (block > vhd->header.max_bat_size) { 255 | fprintf(stderr, "block %s past end of file\n", 256 | conv(hex, block)); 257 | return -ERANGE; 258 | } 259 | 260 | return 0; 261 | } 262 | 263 | static int 264 | vhd_print_headers(vhd_context_t *vhd, int hex) 265 | { 266 | int err; 267 | 268 | vhd_print_footer(&vhd->footer, hex); 269 | 270 | if (vhd_type_dynamic(vhd)) { 271 | vhd_print_header(vhd, &vhd->header, hex); 272 | 273 | if (vhd->footer.type == HD_TYPE_DIFF) 274 | vhd_print_parent_locators(vhd, hex); 275 | 276 | if (vhd_has_batmap(vhd)) { 277 | err = vhd_get_batmap(vhd); 278 | if (err) { 279 | printf("failed to get batmap header\n"); 280 | return err; 281 | } 282 | 283 | vhd_print_batmap_header(&vhd->batmap, hex); 284 | } 285 | } 286 | 287 | return 0; 288 | } 289 | 290 | static int 291 | vhd_dump_headers(const char *name, int hex) 292 | { 293 | vhd_context_t vhd; 294 | 295 | libvhd_set_log_level(1); 296 | memset(&vhd, 0, sizeof(vhd)); 297 | 298 | printf("\n%s appears invalid; dumping headers\n\n", name); 299 | 300 | vhd.fd = open(name, O_DIRECT | O_LARGEFILE | O_RDONLY); 301 | if (vhd.fd == -1) 302 | return -errno; 303 | 304 | vhd.file = strdup(name); 305 | 306 | vhd_read_footer(&vhd, &vhd.footer); 307 | vhd_read_header(&vhd, &vhd.header); 308 | 309 | vhd_print_footer(&vhd.footer, hex); 310 | vhd_print_header(&vhd, &vhd.header, hex); 311 | 312 | close(vhd.fd); 313 | free(vhd.file); 314 | 315 | return 0; 316 | } 317 | 318 | static int 319 | vhd_print_logical_to_physical(vhd_context_t *vhd, 320 | uint64_t sector, int count, int hex) 321 | { 322 | int i; 323 | uint32_t blk, lsec; 324 | uint64_t cur, offset; 325 | 326 | if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) { 327 | fprintf(stderr, "sector %s past end of file\n", 328 | conv(hex, sector + count)); 329 | return -ERANGE; 330 | } 331 | 332 | for (i = 0; i < count; i++) { 333 | cur = sector + i; 334 | blk = cur / vhd->spb; 335 | lsec = cur % vhd->spb; 336 | offset = vhd->bat.bat[blk]; 337 | 338 | if (offset != DD_BLK_UNUSED) { 339 | offset += lsec + 1; 340 | offset = vhd_sectors_to_bytes(offset); 341 | } 342 | 343 | printf("logical sector %s: ", conv(hex, cur)); 344 | printf("block number: %s, ", conv(hex, blk)); 345 | printf("sector offset: %s, ", conv(hex, lsec)); 346 | printf("file offset: %s\n", (offset == DD_BLK_UNUSED ? 347 | "not allocated" : conv(hex, offset))); 348 | } 349 | 350 | return 0; 351 | } 352 | 353 | static int 354 | vhd_print_bat(vhd_context_t *vhd, uint64_t block, int count, int hex) 355 | { 356 | int i; 357 | uint64_t cur, offset; 358 | 359 | if (check_block_range(vhd, block + count, hex)) 360 | return -ERANGE; 361 | 362 | for (i = 0; i < count; i++) { 363 | cur = block + i; 364 | offset = vhd->bat.bat[cur]; 365 | 366 | printf("block: %s: ", conv(hex, cur)); 367 | printf("offset: %s\n", 368 | (offset == DD_BLK_UNUSED ? "not allocated" : 369 | conv(hex, vhd_sectors_to_bytes(offset)))); 370 | } 371 | 372 | return 0; 373 | } 374 | 375 | static inline void 376 | write_full(int fd, void* buf, size_t count) 377 | { 378 | ssize_t num_written = 0; 379 | if (!buf) return; 380 | 381 | 382 | while(count > 0) { 383 | 384 | num_written = write(fd, buf, count); 385 | if (num_written == -1) { 386 | if (errno == EINTR) 387 | continue; 388 | else 389 | return; 390 | } 391 | 392 | count -= num_written; 393 | buf += num_written; 394 | } 395 | } 396 | 397 | static int 398 | vhd_print_bitmap(vhd_context_t *vhd, uint64_t block, int count, int hex) 399 | { 400 | char *buf; 401 | int i, err; 402 | uint64_t cur; 403 | 404 | if (check_block_range(vhd, block + count, hex)) 405 | return -ERANGE; 406 | 407 | for (i = 0; i < count; i++) { 408 | cur = block + i; 409 | 410 | if (vhd->bat.bat[cur] == DD_BLK_UNUSED) { 411 | printf("block %s not allocated\n", conv(hex, cur)); 412 | continue; 413 | } 414 | 415 | err = vhd_read_bitmap(vhd, cur, &buf); 416 | if (err) 417 | goto out; 418 | 419 | write_full(STDOUT_FILENO, buf, 420 | vhd_sectors_to_bytes(vhd->bm_secs)); 421 | free(buf); 422 | } 423 | 424 | err = 0; 425 | out: 426 | return err; 427 | } 428 | 429 | static int 430 | vhd_test_bitmap(vhd_context_t *vhd, uint64_t sector, int count, int hex) 431 | { 432 | char *buf; 433 | uint64_t cur; 434 | int i, err, bit; 435 | uint32_t blk, bm_blk, sec; 436 | 437 | if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) { 438 | printf("sector %s past end of file\n", conv(hex, sector)); 439 | return -ERANGE; 440 | } 441 | 442 | bm_blk = -1; 443 | buf = NULL; 444 | 445 | for (i = 0; i < count; i++) { 446 | cur = sector + i; 447 | blk = cur / vhd->spb; 448 | sec = cur % vhd->spb; 449 | 450 | if (blk != bm_blk) { 451 | bm_blk = blk; 452 | free(buf); 453 | buf = NULL; 454 | 455 | if (vhd->bat.bat[blk] != DD_BLK_UNUSED) { 456 | err = vhd_read_bitmap(vhd, blk, &buf); 457 | if (err) 458 | goto out; 459 | } 460 | } 461 | 462 | if (vhd->bat.bat[blk] == DD_BLK_UNUSED) 463 | bit = 0; 464 | else 465 | bit = vhd_bitmap_test(vhd, buf, blk); 466 | 467 | print: 468 | printf("block %s: ", conv(hex, blk)); 469 | printf("sec: %s: %d\n", conv(hex, sec), bit); 470 | } 471 | 472 | err = 0; 473 | out: 474 | free(buf); 475 | return err; 476 | } 477 | 478 | static int 479 | vhd_print_batmap(vhd_context_t *vhd) 480 | { 481 | int err; 482 | size_t size; 483 | 484 | err = vhd_get_batmap(vhd); 485 | if (err) { 486 | printf("failed to read batmap: %d\n", err); 487 | return err; 488 | } 489 | 490 | size = vhd_sectors_to_bytes(vhd->batmap.header.batmap_size); 491 | write_full(STDOUT_FILENO, vhd->batmap.map, size); 492 | 493 | return 0; 494 | } 495 | 496 | static int 497 | vhd_test_batmap(vhd_context_t *vhd, uint64_t block, int count, int hex) 498 | { 499 | int i, err; 500 | uint64_t cur; 501 | 502 | if (check_block_range(vhd, block + count, hex)) 503 | return -ERANGE; 504 | 505 | err = vhd_get_batmap(vhd); 506 | if (err) { 507 | fprintf(stderr, "failed to get batmap\n"); 508 | return err; 509 | } 510 | 511 | for (i = 0; i < count; i++) { 512 | cur = block + i; 513 | fprintf(stderr, "batmap for block %s: %d\n", conv(hex, cur), 514 | vhd_batmap_test(vhd, &vhd->batmap, cur)); 515 | } 516 | 517 | return 0; 518 | } 519 | 520 | static int 521 | vhd_print_data(vhd_context_t *vhd, uint64_t block, int count, int hex) 522 | { 523 | char *buf; 524 | int i, err; 525 | uint64_t cur; 526 | 527 | err = 0; 528 | 529 | if (check_block_range(vhd, block + count, hex)) 530 | return -ERANGE; 531 | 532 | for (i = 0; i < count; i++) { 533 | cur = block + i; 534 | 535 | if (vhd->bat.bat[cur] == DD_BLK_UNUSED) { 536 | printf("block %s not allocated\n", conv(hex, cur)); 537 | continue; 538 | } 539 | 540 | err = vhd_read_block(vhd, cur, &buf); 541 | if (err) 542 | break; 543 | 544 | write_full(STDOUT_FILENO, buf, vhd->header.block_size); 545 | free(buf); 546 | } 547 | 548 | return err; 549 | } 550 | 551 | static int 552 | vhd_read_data(vhd_context_t *vhd, uint64_t sec, int count, int hex) 553 | { 554 | char *buf; 555 | uint64_t cur; 556 | int err, max, secs; 557 | 558 | if (vhd_sectors_to_bytes(sec + count) > vhd->footer.curr_size) 559 | return -ERANGE; 560 | 561 | max = MIN(vhd_sectors_to_bytes(count), VHD_BLOCK_SIZE); 562 | err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, max); 563 | if (err) 564 | return -err; 565 | 566 | cur = sec; 567 | while (count) { 568 | secs = MIN((max >> VHD_SECTOR_SHIFT), count); 569 | err = vhd_io_read(vhd, buf, cur, secs); 570 | if (err) 571 | break; 572 | 573 | write_full(STDOUT_FILENO, buf, vhd_sectors_to_bytes(secs)); 574 | 575 | cur += secs; 576 | count -= secs; 577 | } 578 | 579 | free(buf); 580 | return err; 581 | } 582 | 583 | int 584 | vhd_util_read(int argc, char **argv) 585 | { 586 | char *name; 587 | vhd_context_t vhd; 588 | int c, err, headers, hex; 589 | uint64_t bat, bitmap, tbitmap, batmap, tbatmap, data, lsec, count, read; 590 | 591 | err = 0; 592 | hex = 0; 593 | headers = 0; 594 | count = 1; 595 | bat = -1; 596 | bitmap = -1; 597 | tbitmap = -1; 598 | batmap = -1; 599 | tbatmap = -1; 600 | data = -1; 601 | lsec = -1; 602 | read = -1; 603 | name = NULL; 604 | 605 | if (!argc || !argv) 606 | goto usage; 607 | 608 | optind = 0; 609 | while ((c = getopt(argc, argv, "n:pt:b:m:i:aj:d:c:r:xh")) != -1) { 610 | switch(c) { 611 | case 'n': 612 | name = optarg; 613 | break; 614 | case 'p': 615 | headers = 1; 616 | break; 617 | case 't': 618 | lsec = strtoul(optarg, NULL, 10); 619 | break; 620 | case 'b': 621 | bat = strtoull(optarg, NULL, 10); 622 | break; 623 | case 'm': 624 | bitmap = strtoull(optarg, NULL, 10); 625 | break; 626 | case 'i': 627 | tbitmap = strtoul(optarg, NULL, 10); 628 | break; 629 | case 'a': 630 | batmap = 1; 631 | break; 632 | case 'j': 633 | tbatmap = strtoull(optarg, NULL, 10); 634 | break; 635 | case 'd': 636 | data = strtoull(optarg, NULL, 10); 637 | break; 638 | case 'r': 639 | read = strtoull(optarg, NULL, 10); 640 | break; 641 | case 'c': 642 | count = strtoul(optarg, NULL, 10); 643 | break; 644 | case 'x': 645 | hex = 1; 646 | break; 647 | case 'h': 648 | default: 649 | goto usage; 650 | } 651 | } 652 | 653 | if (!name || optind != argc) 654 | goto usage; 655 | 656 | err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED); 657 | if (err) { 658 | printf("Failed to open %s: %d\n", name, err); 659 | vhd_dump_headers(name, hex); 660 | return err; 661 | } 662 | 663 | err = vhd_get_bat(&vhd); 664 | if (err) { 665 | printf("Failed to get bat for %s: %d\n", name, err); 666 | goto out; 667 | } 668 | 669 | if (headers) 670 | vhd_print_headers(&vhd, hex); 671 | 672 | if (lsec != -1) { 673 | err = vhd_print_logical_to_physical(&vhd, lsec, count, hex); 674 | if (err) 675 | goto out; 676 | } 677 | 678 | if (bat != -1) { 679 | err = vhd_print_bat(&vhd, bat, count, hex); 680 | if (err) 681 | goto out; 682 | } 683 | 684 | if (bitmap != -1) { 685 | err = vhd_print_bitmap(&vhd, bitmap, count, hex); 686 | if (err) 687 | goto out; 688 | } 689 | 690 | if (tbitmap != -1) { 691 | err = vhd_test_bitmap(&vhd, tbitmap, count, hex); 692 | if (err) 693 | goto out; 694 | } 695 | 696 | if (batmap != -1) { 697 | err = vhd_print_batmap(&vhd); 698 | if (err) 699 | goto out; 700 | } 701 | 702 | if (tbatmap != -1) { 703 | err = vhd_test_batmap(&vhd, tbatmap, count, hex); 704 | if (err) 705 | goto out; 706 | } 707 | 708 | if (data != -1) { 709 | err = vhd_print_data(&vhd, data, count, hex); 710 | if (err) 711 | goto out; 712 | } 713 | 714 | if (read != -1) { 715 | err = vhd_read_data(&vhd, read, count, hex); 716 | if (err) 717 | goto out; 718 | } 719 | 720 | err = 0; 721 | 722 | out: 723 | vhd_close(&vhd); 724 | return err; 725 | 726 | usage: 727 | printf("options:\n" 728 | "-h help\n" 729 | "-n name\n" 730 | "-p print VHD headers\n" 731 | "-t sec translate logical sector to VHD location\n" 732 | "-b blk print bat entry\n" 733 | "-m blk print bitmap\n" 734 | "-i sec test bitmap for logical sector\n" 735 | "-a print batmap\n" 736 | "-j blk test batmap for block\n" 737 | "-d blk print data\n" 738 | "-c num num units\n" 739 | "-r sec read num sectors at sec\n" 740 | "-x print in hex\n"); 741 | return EINVAL; 742 | } 743 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-repair.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "libvhd.h" 34 | 35 | int 36 | vhd_util_repair(int argc, char **argv) 37 | { 38 | char *name; 39 | int err, c; 40 | off_t eof; 41 | vhd_context_t vhd; 42 | 43 | name = NULL; 44 | 45 | if (!argc || !argv) 46 | goto usage; 47 | 48 | optind = 0; 49 | while ((c = getopt(argc, argv, "n:h")) != -1) { 50 | switch (c) { 51 | case 'n': 52 | name = optarg; 53 | break; 54 | case 'h': 55 | default: 56 | goto usage; 57 | } 58 | } 59 | 60 | if (!name || optind != argc) 61 | goto usage; 62 | 63 | err = vhd_open(&vhd, name, VHD_OPEN_RDWR); 64 | if (err) { 65 | printf("error opening %s: %d\n", name, err); 66 | return err; 67 | } 68 | 69 | err = vhd_end_of_data(&vhd, &eof); 70 | if (err) { 71 | printf("error finding end of data: %d\n", err); 72 | goto done; 73 | } 74 | 75 | err = vhd_write_footer_at(&vhd, &vhd.footer, eof); 76 | 77 | done: 78 | vhd_close(&vhd); 79 | return err; 80 | 81 | usage: 82 | printf("options: <-n name> [-h help]\n"); 83 | return -EINVAL; 84 | } 85 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-resize.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "libvhd-journal.h" 38 | 39 | #if 1 40 | #define DFPRINTF(_f, _a...) fprintf(stdout, _f, ##_a) 41 | #else 42 | #define DFPRINTF(_f, _a...) ((void)0) 43 | #endif 44 | 45 | #define EPRINTF(_f, _a...) \ 46 | do { \ 47 | syslog(LOG_INFO, "%s: " _f, __func__, ##_a); \ 48 | DFPRINTF(_f, _a); \ 49 | } while (0) 50 | 51 | typedef struct vhd_block { 52 | uint32_t block; 53 | uint32_t offset; 54 | } vhd_block_t; 55 | 56 | TEST_FAIL_EXTERN_VARS; 57 | 58 | static inline uint32_t 59 | secs_to_blocks_down(vhd_context_t *vhd, uint64_t secs) 60 | { 61 | return secs / vhd->spb; 62 | } 63 | 64 | static uint32_t 65 | secs_to_blocks_up(vhd_context_t *vhd, uint64_t secs) 66 | { 67 | uint32_t blocks; 68 | 69 | blocks = secs / vhd->spb; 70 | if (secs % vhd->spb) 71 | blocks++; 72 | 73 | return blocks; 74 | } 75 | 76 | static int 77 | vhd_fixed_shrink(vhd_journal_t *journal, uint64_t secs) 78 | { 79 | int err; 80 | uint64_t new_eof; 81 | vhd_context_t *vhd; 82 | 83 | vhd = &journal->vhd; 84 | 85 | new_eof = vhd->footer.curr_size - vhd_sectors_to_bytes(secs); 86 | if (new_eof <= sizeof(vhd_footer_t)) 87 | return -EINVAL; 88 | 89 | err = ftruncate(vhd->fd, new_eof); 90 | if (err) 91 | return errno; 92 | 93 | vhd->footer.curr_size = new_eof; 94 | return vhd_write_footer(vhd, &vhd->footer); 95 | } 96 | 97 | static int 98 | vhd_write_zeros(vhd_journal_t *journal, off_t off, uint64_t size) 99 | { 100 | int err; 101 | char *buf; 102 | vhd_context_t *vhd; 103 | uint64_t bytes, map; 104 | 105 | vhd = &journal->vhd; 106 | map = MIN(size, VHD_BLOCK_SIZE); 107 | 108 | err = vhd_seek(vhd, off, SEEK_SET); 109 | if (err) 110 | return err; 111 | 112 | buf = mmap(0, map, PROT_READ, MAP_SHARED | MAP_ANON, -1, 0); 113 | if (buf == MAP_FAILED) 114 | return -errno; 115 | 116 | do { 117 | bytes = MIN(size, map); 118 | 119 | err = vhd_write(vhd, buf, bytes); 120 | if (err) 121 | break; 122 | 123 | size -= bytes; 124 | } while (size); 125 | 126 | munmap(buf, map); 127 | 128 | return err; 129 | } 130 | 131 | static int 132 | vhd_fixed_grow(vhd_journal_t *journal, uint64_t secs) 133 | { 134 | int err; 135 | vhd_context_t *vhd; 136 | uint64_t size, eof, new_eof; 137 | 138 | size = vhd_sectors_to_bytes(secs); 139 | vhd = &journal->vhd; 140 | 141 | err = vhd_seek(vhd, 0, SEEK_END); 142 | if (err) 143 | goto out; 144 | 145 | eof = vhd_position(vhd); 146 | if (eof == (off_t)-1) { 147 | err = -errno; 148 | goto out; 149 | } 150 | 151 | err = vhd_write_zeros(journal, eof - sizeof(vhd_footer_t), size); 152 | if (err) 153 | goto out; 154 | 155 | new_eof = eof + size; 156 | err = vhd_seek(vhd, new_eof, SEEK_SET); 157 | if (err) 158 | goto out; 159 | 160 | vhd->footer.curr_size += size; 161 | err = vhd_write_footer(vhd, &vhd->footer); 162 | if (err) 163 | goto out; 164 | 165 | err = 0; 166 | 167 | out: 168 | return err; 169 | } 170 | 171 | static int 172 | vhd_fixed_resize(vhd_journal_t *journal, uint64_t size) 173 | { 174 | int err; 175 | vhd_context_t *vhd; 176 | uint64_t cur_secs, new_secs; 177 | 178 | vhd = &journal->vhd; 179 | cur_secs = vhd->footer.curr_size >> VHD_SECTOR_SHIFT; 180 | new_secs = size << (20 - VHD_SECTOR_SHIFT); 181 | 182 | if (cur_secs == new_secs) 183 | return 0; 184 | else if (cur_secs > new_secs) 185 | err = vhd_fixed_shrink(journal, cur_secs - new_secs); 186 | else 187 | err = vhd_fixed_grow(journal, new_secs - cur_secs); 188 | 189 | return err; 190 | } 191 | 192 | static inline void 193 | swap(vhd_block_t *list, int a, int b) 194 | { 195 | vhd_block_t tmp; 196 | 197 | tmp = list[a]; 198 | list[a] = list[b]; 199 | list[b] = tmp; 200 | } 201 | 202 | static int 203 | partition(vhd_block_t *list, int left, int right, int pidx) 204 | { 205 | int i, sidx; 206 | long long pval; 207 | 208 | sidx = left; 209 | pval = list[pidx].offset; 210 | swap(list, pidx, right); 211 | 212 | for (i = left; i < right; i++) 213 | if (list[i].offset >= pval) { 214 | swap(list, sidx, i); 215 | ++sidx; 216 | } 217 | 218 | swap(list, right, sidx); 219 | return sidx; 220 | } 221 | 222 | static void 223 | quicksort(vhd_block_t *list, int left, int right) 224 | { 225 | int pidx, new_pidx; 226 | 227 | if (right < left) 228 | return; 229 | 230 | pidx = left; 231 | new_pidx = partition(list, left, right, pidx); 232 | quicksort(list, left, new_pidx - 1); 233 | quicksort(list, new_pidx + 1, right); 234 | } 235 | 236 | static int 237 | vhd_move_block(vhd_journal_t *journal, uint32_t src, off_t offset) 238 | { 239 | int err; 240 | char *buf; 241 | size_t size; 242 | vhd_context_t *vhd; 243 | off_t off, src_off; 244 | 245 | buf = NULL; 246 | vhd = &journal->vhd; 247 | off = offset; 248 | size = vhd_sectors_to_bytes(vhd->bm_secs); 249 | src_off = vhd->bat.bat[src]; 250 | 251 | if (src_off == DD_BLK_UNUSED) 252 | return -EINVAL; 253 | src_off = vhd_sectors_to_bytes(src_off); 254 | 255 | err = vhd_journal_add_block(journal, src, 256 | VHD_JOURNAL_DATA | VHD_JOURNAL_METADATA); 257 | if (err) 258 | goto out; 259 | 260 | err = vhd_read_bitmap(vhd, src, &buf); 261 | if (err) 262 | goto out; 263 | 264 | err = vhd_seek(vhd, off, SEEK_SET); 265 | if (err) 266 | goto out; 267 | 268 | err = vhd_write(vhd, buf, size); 269 | if (err) 270 | goto out; 271 | 272 | free(buf); 273 | buf = NULL; 274 | off += size; 275 | size = vhd_sectors_to_bytes(vhd->spb); 276 | 277 | err = vhd_read_block(vhd, src, &buf); 278 | if (err) 279 | goto out; 280 | 281 | err = vhd_seek(vhd, off, SEEK_SET); 282 | if (err) 283 | goto out; 284 | 285 | err = vhd_write(vhd, buf, size); 286 | if (err) 287 | goto out; 288 | 289 | vhd->bat.bat[src] = offset >> VHD_SECTOR_SHIFT; 290 | 291 | err = vhd_write_zeros(journal, src_off, 292 | vhd_sectors_to_bytes(vhd->bm_secs + vhd->spb)); 293 | 294 | out: 295 | free(buf); 296 | return err; 297 | } 298 | 299 | static int 300 | vhd_clobber_block(vhd_journal_t *journal, uint32_t src, uint32_t dest) 301 | { 302 | int err; 303 | off_t off; 304 | vhd_context_t *vhd; 305 | 306 | vhd = &journal->vhd; 307 | off = vhd_sectors_to_bytes(vhd->bat.bat[dest]); 308 | 309 | err = vhd_journal_add_block(journal, dest, 310 | VHD_JOURNAL_DATA | VHD_JOURNAL_METADATA); 311 | if (err) 312 | return err; 313 | 314 | err = vhd_move_block(journal, src, off); 315 | if (err) 316 | return err; 317 | 318 | vhd->bat.bat[dest] = DD_BLK_UNUSED; 319 | 320 | return 0; 321 | } 322 | 323 | /* 324 | * remove a list of blocks from the vhd file 325 | * if a block to be removed: 326 | * - resides at the end of the file: simply clear its bat entry 327 | * - resides elsewhere: move the last block in the file into its position 328 | * and update the bat to reflect this 329 | */ 330 | static int 331 | vhd_defrag_shrink(vhd_journal_t *journal, 332 | vhd_block_t *original_free_list, int free_cnt) 333 | { 334 | vhd_context_t *vhd; 335 | int i, j, free_idx, err; 336 | vhd_block_t *blocks, *free_list; 337 | 338 | err = 0; 339 | blocks = NULL; 340 | free_list = NULL; 341 | vhd = &journal->vhd; 342 | 343 | blocks = malloc(vhd->bat.entries * sizeof(vhd_block_t)); 344 | if (!blocks) { 345 | err = -ENOMEM; 346 | goto out; 347 | } 348 | 349 | free_list = malloc(free_cnt * sizeof(vhd_block_t)); 350 | if (!free_list) { 351 | err = -ENOMEM; 352 | goto out; 353 | } 354 | 355 | for (i = 0; i < vhd->bat.entries; i++) { 356 | blocks[i].block = i; 357 | blocks[i].offset = vhd->bat.bat[i]; 358 | } 359 | 360 | memcpy(free_list, original_free_list, 361 | free_cnt * sizeof(vhd_block_t)); 362 | 363 | /* sort both the to-free list and the bat list 364 | * in order of descending file offset */ 365 | quicksort(free_list, 0, free_cnt - 1); 366 | quicksort(blocks, 0, vhd->bat.entries - 1); 367 | 368 | for (i = 0, free_idx = 0; 369 | i < vhd->bat.entries && free_idx < free_cnt; i++) { 370 | vhd_block_t *b = blocks + i; 371 | 372 | if (b->offset == DD_BLK_UNUSED) 373 | continue; 374 | 375 | for (j = free_idx; j < free_cnt; j++) 376 | if (b->block == free_list[j].block) { 377 | /* the last block in the file is in the list of 378 | * blocks to remove; no need to shuffle the 379 | * data -- just clear the bat entry */ 380 | vhd->bat.bat[free_list[j].block] = DD_BLK_UNUSED; 381 | free_idx++; 382 | continue; 383 | } 384 | 385 | err = vhd_clobber_block(journal, b->block, 386 | free_list[free_idx++].block); 387 | if (err) 388 | goto out; 389 | } 390 | 391 | /* clear any bat entries for blocks we did not shuffle */ 392 | for (i = free_idx; i < free_cnt; i++) 393 | vhd->bat.bat[free_list[i].block] = DD_BLK_UNUSED; 394 | 395 | out: 396 | free(blocks); 397 | free(free_list); 398 | 399 | return err; 400 | } 401 | 402 | static int 403 | vhd_clear_bat_entries(vhd_journal_t *journal, uint32_t entries) 404 | { 405 | int i, err; 406 | vhd_context_t *vhd; 407 | off_t orig_map_off, new_map_off; 408 | uint32_t orig_entries, new_entries; 409 | 410 | vhd = &journal->vhd; 411 | orig_entries = vhd->header.max_bat_size; 412 | new_entries = orig_entries - entries; 413 | 414 | if (vhd_has_batmap(vhd)) { 415 | err = vhd_batmap_header_offset(vhd, &orig_map_off); 416 | if (err) 417 | return err; 418 | } 419 | 420 | /* update header */ 421 | vhd->header.max_bat_size = new_entries; 422 | err = vhd_write_header(vhd, &vhd->header); 423 | if (err) 424 | return err; 425 | 426 | /* update footer */ 427 | vhd->footer.curr_size = (uint64_t)new_entries * vhd->header.block_size; 428 | vhd->footer.geometry = vhd_chs(vhd->footer.curr_size); 429 | err = vhd_write_footer(vhd, &vhd->footer); 430 | if (err) 431 | return err; 432 | 433 | /* update bat -- we don't reclaim space, just clear entries */ 434 | for (i = new_entries; i < orig_entries; i++) 435 | vhd->bat.bat[i] = 0; 436 | 437 | err = vhd_write_bat(vhd, &vhd->bat); 438 | if (err) 439 | return err; 440 | 441 | /* update this after write_bat so the end of the bat is zeored */ 442 | vhd->bat.entries = new_entries; 443 | 444 | if (!vhd_has_batmap(vhd)) 445 | return 0; 446 | 447 | /* zero out old batmap header if new header has moved */ 448 | err = vhd_batmap_header_offset(vhd, &new_map_off); 449 | if (err) 450 | return err; 451 | 452 | if (orig_map_off != new_map_off) { 453 | size_t size; 454 | 455 | size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr)); 456 | 457 | err = vhd_write_zeros(journal, orig_map_off, size); 458 | if (err) 459 | return err; 460 | } 461 | 462 | /* update batmap -- clear entries for freed blocks */ 463 | for (i = new_entries; i < orig_entries; i++) 464 | vhd_batmap_clear(vhd, &vhd->batmap, i); 465 | 466 | err = vhd_write_batmap(vhd, &vhd->batmap); 467 | if (err) 468 | return err; 469 | 470 | return 0; 471 | } 472 | 473 | static int 474 | vhd_dynamic_shrink(vhd_journal_t *journal, uint64_t secs) 475 | { 476 | off_t eof; 477 | uint32_t blocks; 478 | vhd_context_t *vhd; 479 | int i, j, err, free_cnt; 480 | struct vhd_block *free_list; 481 | 482 | printf("dynamic shrink not fully implemented\n"); 483 | return -ENOSYS; 484 | 485 | eof = 0; 486 | free_cnt = 0; 487 | free_list = NULL; 488 | vhd = &journal->vhd; 489 | 490 | blocks = secs_to_blocks_down(vhd, secs); 491 | if (blocks == 0) 492 | return 0; 493 | 494 | if (vhd_has_batmap(vhd)) { 495 | err = vhd_get_batmap(vhd); 496 | if (err) 497 | return err; 498 | } 499 | 500 | free_list = malloc(blocks * sizeof(struct vhd_block)); 501 | if (!free_list) 502 | return -ENOMEM; 503 | 504 | for (i = vhd->bat.entries - 1, j = 0; i >= 0 && j < blocks; i--, j++) { 505 | uint32_t blk = vhd->bat.bat[i]; 506 | 507 | if (blk != DD_BLK_UNUSED) { 508 | free_list[free_cnt].block = i; 509 | free_list[free_cnt].offset = blk; 510 | free_cnt++; 511 | } 512 | } 513 | 514 | if (free_cnt) { 515 | err = vhd_defrag_shrink(journal, free_list, free_cnt); 516 | if (err) 517 | goto out; 518 | } 519 | 520 | err = vhd_clear_bat_entries(journal, blocks); 521 | if (err) 522 | goto out; 523 | 524 | /* remove data beyond footer */ 525 | err = vhd_end_of_data(vhd, &eof); 526 | if (err) 527 | goto out; 528 | 529 | err = ftruncate(vhd->fd, eof + sizeof(vhd_footer_t)); 530 | if (err) { 531 | err = -errno; 532 | goto out; 533 | } 534 | 535 | err = 0; 536 | 537 | out: 538 | free(free_list); 539 | return err; 540 | } 541 | 542 | static inline void 543 | vhd_first_data_block(vhd_context_t *vhd, vhd_block_t *block) 544 | { 545 | int i; 546 | uint32_t blk; 547 | 548 | memset(block, 0, sizeof(vhd_block_t)); 549 | 550 | for (i = 0; i < vhd->bat.entries; i++) { 551 | blk = vhd->bat.bat[i]; 552 | 553 | if (blk != DD_BLK_UNUSED) { 554 | if (!block->offset || blk < block->offset) { 555 | block->block = i; 556 | block->offset = blk; 557 | } 558 | } 559 | } 560 | } 561 | 562 | static inline uint32_t 563 | vhd_next_block_offset(vhd_context_t *vhd) 564 | { 565 | int i; 566 | uint32_t blk, end, spp, next; 567 | 568 | next = 0; 569 | spp = getpagesize() >> VHD_SECTOR_SHIFT; 570 | 571 | for (i = 0; i < vhd->bat.entries; i++) { 572 | blk = vhd->bat.bat[i]; 573 | 574 | if (blk != DD_BLK_UNUSED) { 575 | end = blk + vhd->spb + vhd->bm_secs; 576 | next = MAX(next, end); 577 | } 578 | } 579 | 580 | return next; 581 | } 582 | 583 | static inline int 584 | in_range(off_t off, off_t start, off_t size) 585 | { 586 | return (start < off && start + size > off); 587 | } 588 | 589 | #define SKIP_HEADER 0x01 590 | #define SKIP_BAT 0x02 591 | #define SKIP_BATMAP 0x04 592 | #define SKIP_PLOC 0x08 593 | #define SKIP_DATA 0x10 594 | 595 | static inline int 596 | skip_check(int mode, int type) 597 | { 598 | return mode & type; 599 | } 600 | 601 | static int 602 | vhd_check_for_clobber(vhd_context_t *vhd, off_t off, int mode) 603 | { 604 | int i, n; 605 | char *msg; 606 | size_t size; 607 | vhd_block_t fb; 608 | vhd_parent_locator_t *loc; 609 | 610 | msg = NULL; 611 | 612 | if (!vhd_type_dynamic(vhd)) 613 | return 0; 614 | 615 | if (off < VHD_SECTOR_SIZE) { 616 | msg = "backup footer"; 617 | goto fail; 618 | } 619 | 620 | if (!skip_check(mode, SKIP_HEADER)) 621 | if (in_range(off, 622 | vhd->footer.data_offset, sizeof(vhd_header_t))) { 623 | msg = "header"; 624 | goto fail; 625 | } 626 | 627 | if (!skip_check(mode, SKIP_BAT)) 628 | if (in_range(off, vhd->header.table_offset, 629 | vhd_bytes_padded(vhd->header.max_bat_size * 630 | sizeof(uint32_t)))) { 631 | msg = "bat"; 632 | goto fail; 633 | } 634 | 635 | if (!skip_check(mode, SKIP_BATMAP)) 636 | if (vhd_has_batmap(vhd) && 637 | in_range(off, vhd->batmap.header.batmap_offset, 638 | vhd_bytes_padded(vhd->batmap.header.batmap_size))) { 639 | msg = "batmap"; 640 | goto fail; 641 | } 642 | 643 | if (!skip_check(mode, SKIP_PLOC)) { 644 | n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t); 645 | for (i = 0; i < n; i++) { 646 | loc = vhd->header.loc + i; 647 | if (loc->code == PLAT_CODE_NONE) 648 | continue; 649 | 650 | size = vhd_parent_locator_size(loc); 651 | if (in_range(off, loc->data_offset, size)) { 652 | msg = "parent locator"; 653 | goto fail; 654 | } 655 | } 656 | } 657 | 658 | if (!skip_check(mode, SKIP_DATA)) { 659 | vhd_first_data_block(vhd, &fb); 660 | if (fb.offset && in_range(off, 661 | vhd_sectors_to_bytes(fb.offset), 662 | VHD_BLOCK_SIZE)) { 663 | msg = "data block"; 664 | goto fail; 665 | } 666 | } 667 | 668 | return 0; 669 | 670 | fail: 671 | EPRINTF("write to 0x%08"PRIx64" would clobber %s\n", off, msg); 672 | return -EINVAL; 673 | } 674 | 675 | /* 676 | * take any metadata after the bat (@eob) and shift it 677 | */ 678 | static int 679 | vhd_shift_metadata(vhd_journal_t *journal, off_t eob, 680 | size_t bat_needed, size_t map_needed) 681 | { 682 | int i, n, err; 683 | vhd_context_t *vhd; 684 | size_t size_needed; 685 | char *buf, **locators; 686 | vhd_parent_locator_t *loc; 687 | 688 | vhd = &journal->vhd; 689 | size_needed = bat_needed + map_needed; 690 | 691 | n = sizeof(vhd->header.loc) / sizeof(vhd_parent_locator_t); 692 | 693 | locators = calloc(n, sizeof(char *)); 694 | if (!locators) 695 | return -ENOMEM; 696 | 697 | for (i = 0; i < n; i++) { 698 | size_t size; 699 | 700 | loc = vhd->header.loc + i; 701 | if (loc->code == PLAT_CODE_NONE) 702 | continue; 703 | 704 | if (loc->data_offset < eob) 705 | continue; 706 | 707 | size = vhd_parent_locator_size(loc); 708 | err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size); 709 | if (err) { 710 | err = -err; 711 | buf = NULL; 712 | goto out; 713 | } 714 | 715 | err = vhd_seek(vhd, loc->data_offset, SEEK_SET); 716 | if (err) 717 | goto out; 718 | 719 | err = vhd_read(vhd, buf, size); 720 | if (err) 721 | goto out; 722 | 723 | locators[i] = buf; 724 | } 725 | 726 | for (i = 0; i < n; i++) { 727 | off_t off; 728 | size_t size; 729 | 730 | if (!locators[i]) 731 | continue; 732 | 733 | loc = vhd->header.loc + i; 734 | off = loc->data_offset + size_needed; 735 | size = vhd_parent_locator_size(loc); 736 | 737 | if (vhd_check_for_clobber(vhd, off + size, SKIP_PLOC)) { 738 | EPRINTF("%s: shifting locator %d would clobber data\n", 739 | vhd->file, i); 740 | return -EINVAL; 741 | } 742 | 743 | err = vhd_seek(vhd, off, SEEK_SET); 744 | if (err) 745 | goto out; 746 | 747 | err = vhd_write(vhd, locators[i], size); 748 | if (err) 749 | goto out; 750 | 751 | free(locators[i]); 752 | locators[i] = NULL; 753 | loc->data_offset = off; 754 | 755 | /* write the new header after writing the new bat */ 756 | } 757 | 758 | if (vhd_has_batmap(vhd) && vhd->batmap.header.batmap_offset > eob) { 759 | vhd->batmap.header.batmap_offset += bat_needed; 760 | 761 | /* write the new batmap after writing the new bat */ 762 | } 763 | 764 | err = 0; 765 | 766 | out: 767 | for (i = 0; i < n; i++) 768 | free(locators[i]); 769 | free(locators); 770 | 771 | return err; 772 | } 773 | 774 | static int 775 | vhd_add_bat_entries(vhd_journal_t *journal, int entries) 776 | { 777 | int i, err; 778 | off_t off; 779 | vhd_bat_t new_bat; 780 | vhd_context_t *vhd; 781 | uint32_t new_entries; 782 | vhd_batmap_t new_batmap; 783 | uint64_t bat_size, new_bat_size, map_size, new_map_size; 784 | 785 | vhd = &journal->vhd; 786 | new_entries = vhd->header.max_bat_size + entries; 787 | 788 | bat_size = vhd_bytes_padded(vhd->header.max_bat_size * 789 | sizeof(uint32_t)); 790 | new_bat_size = vhd_bytes_padded(new_entries * sizeof(uint32_t)); 791 | 792 | map_size = vhd_bytes_padded((vhd->header.max_bat_size + 7) >> 3); 793 | new_map_size = vhd_bytes_padded((new_entries + 7) >> 3); 794 | 795 | off = vhd->header.table_offset + new_bat_size; 796 | if (vhd_check_for_clobber(vhd, off, SKIP_BAT | SKIP_BATMAP)) { 797 | EPRINTF("%s: writing new bat of 0x%"PRIx64" bytes " 798 | "at 0x%08"PRIx64" would clobber data\n", 799 | vhd->file, new_bat_size, vhd->header.table_offset); 800 | return -EINVAL; 801 | } 802 | 803 | if (vhd_has_batmap(vhd)) { 804 | off = vhd->batmap.header.batmap_offset + new_map_size; 805 | if (vhd_check_for_clobber(vhd, off, 0)) { 806 | EPRINTF("%s: writing new batmap of 0x%"PRIx64" bytes" 807 | " at 0x%08"PRIx64" would clobber data\n", vhd->file, 808 | new_map_size, vhd->batmap.header.batmap_offset); 809 | return -EINVAL; 810 | } 811 | } 812 | 813 | /* update header */ 814 | vhd->header.max_bat_size = new_entries; 815 | err = vhd_write_header(vhd, &vhd->header); 816 | if (err) 817 | return err; 818 | 819 | /* update footer */ 820 | vhd->footer.curr_size = (uint64_t)new_entries * vhd->header.block_size; 821 | vhd->footer.geometry = vhd_chs(vhd->footer.curr_size); 822 | vhd->footer.checksum = vhd_checksum_footer(&vhd->footer); 823 | err = vhd_write_footer(vhd, &vhd->footer); 824 | if (err) 825 | return err; 826 | 827 | /* allocate new bat */ 828 | err = posix_memalign((void **)&new_bat.bat, VHD_SECTOR_SIZE, new_bat_size); 829 | if (err) 830 | return -err; 831 | 832 | new_bat.spb = vhd->bat.spb; 833 | new_bat.entries = new_entries; 834 | memcpy(new_bat.bat, vhd->bat.bat, bat_size); 835 | for (i = vhd->bat.entries; i < new_entries; i++) 836 | new_bat.bat[i] = DD_BLK_UNUSED; 837 | 838 | /* write new bat */ 839 | err = vhd_write_bat(vhd, &new_bat); 840 | if (err) { 841 | free(new_bat.bat); 842 | return err; 843 | } 844 | 845 | /* update in-memory bat */ 846 | free(vhd->bat.bat); 847 | vhd->bat = new_bat; 848 | 849 | if (!vhd_has_batmap(vhd)) 850 | return 0; 851 | 852 | /* allocate new batmap */ 853 | err = posix_memalign((void **)&new_batmap.map, 854 | VHD_SECTOR_SIZE, new_map_size); 855 | if (err) 856 | return err; 857 | 858 | new_batmap.header = vhd->batmap.header; 859 | new_batmap.header.batmap_size = secs_round_up_no_zero(new_map_size); 860 | memcpy(new_batmap.map, vhd->batmap.map, map_size); 861 | memset(new_batmap.map + map_size, 0, new_map_size - map_size); 862 | 863 | /* write new batmap */ 864 | err = vhd_write_batmap(vhd, &new_batmap); 865 | if (err) { 866 | free(new_batmap.map); 867 | return err; 868 | } 869 | 870 | /* update in-memory batmap */ 871 | free(vhd->batmap.map); 872 | vhd->batmap = new_batmap; 873 | 874 | return 0; 875 | } 876 | 877 | static int 878 | vhd_dynamic_grow(vhd_journal_t *journal, uint64_t secs) 879 | { 880 | int i, err; 881 | off_t eob, eom; 882 | vhd_context_t *vhd; 883 | vhd_block_t first_block; 884 | uint64_t blocks, size_needed; 885 | uint64_t bat_needed, bat_size, bat_avail, bat_bytes, bat_secs; 886 | uint64_t map_needed, map_size, map_avail, map_bytes, map_secs; 887 | 888 | vhd = &journal->vhd; 889 | 890 | size_needed = 0; 891 | bat_needed = 0; 892 | map_needed = 0; 893 | 894 | /* number of vhd blocks to add */ 895 | blocks = secs_to_blocks_up(vhd, secs); 896 | 897 | /* size in bytes needed for new bat entries */ 898 | bat_needed = blocks * sizeof(uint32_t); 899 | map_needed = (blocks >> 3) + 1; 900 | 901 | /* available bytes in current bat */ 902 | bat_bytes = vhd->header.max_bat_size * sizeof(uint32_t); 903 | bat_secs = secs_round_up_no_zero(bat_bytes); 904 | bat_size = vhd_sectors_to_bytes(bat_secs); 905 | bat_avail = bat_size - bat_bytes; 906 | 907 | if (vhd_has_batmap(vhd)) { 908 | /* avaliable bytes in current batmap */ 909 | map_bytes = (vhd->header.max_bat_size + 7) >> 3; 910 | map_secs = vhd->batmap.header.batmap_size; 911 | map_size = vhd_sectors_to_bytes(map_secs); 912 | map_avail = map_size - map_bytes; 913 | } else { 914 | map_needed = 0; 915 | map_avail = 0; 916 | } 917 | 918 | /* we have enough space already; just extend the bat */ 919 | if (bat_needed <= bat_avail && map_needed <= map_avail) 920 | goto add_entries; 921 | 922 | /* we need to add new sectors to the bat */ 923 | if (bat_needed > bat_avail) { 924 | bat_needed -= bat_avail; 925 | bat_needed = vhd_bytes_padded(bat_needed); 926 | } else 927 | bat_needed = 0; 928 | 929 | /* we need to add new sectors to the batmap */ 930 | if (map_needed > map_avail) { 931 | map_needed -= map_avail; 932 | map_needed = vhd_bytes_padded(map_needed); 933 | } else 934 | map_needed = 0; 935 | 936 | /* how many additional bytes do we need? */ 937 | size_needed = bat_needed + map_needed; 938 | 939 | /* calculate space between end of headers and beginning of data */ 940 | err = vhd_end_of_headers(vhd, &eom); 941 | if (err) 942 | return err; 943 | 944 | eob = vhd->header.table_offset + vhd_sectors_to_bytes(bat_secs); 945 | vhd_first_data_block(vhd, &first_block); 946 | 947 | /* no blocks allocated; just shift post-bat metadata */ 948 | if (!first_block.offset) 949 | goto shift_metadata; 950 | 951 | /* 952 | * not enough space -- 953 | * move vhd data blocks to the end of the file to make room 954 | */ 955 | do { 956 | off_t new_off, bm_size, gap_size; 957 | 958 | new_off = vhd_sectors_to_bytes(vhd_next_block_offset(vhd)); 959 | 960 | /* data region of segment should begin on page boundary */ 961 | bm_size = vhd_sectors_to_bytes(vhd->bm_secs); 962 | if ((new_off + bm_size) % 4096) { 963 | gap_size = 4096 - ((new_off + bm_size) % 4096); 964 | 965 | err = vhd_write_zeros(journal, new_off, gap_size); 966 | if (err) 967 | return err; 968 | 969 | new_off += gap_size; 970 | } 971 | 972 | err = vhd_move_block(journal, first_block.block, new_off); 973 | if (err) 974 | return err; 975 | 976 | vhd_first_data_block(vhd, &first_block); 977 | 978 | } while (eom + size_needed >= vhd_sectors_to_bytes(first_block.offset)); 979 | 980 | TEST_FAIL_AT(FAIL_RESIZE_DATA_MOVED); 981 | 982 | shift_metadata: 983 | /* shift any metadata after the bat to make room for new bat sectors */ 984 | err = vhd_shift_metadata(journal, eob, bat_needed, map_needed); 985 | if (err) 986 | return err; 987 | 988 | TEST_FAIL_AT(FAIL_RESIZE_METADATA_MOVED); 989 | 990 | add_entries: 991 | return vhd_add_bat_entries(journal, blocks); 992 | } 993 | 994 | static int 995 | vhd_dynamic_resize(vhd_journal_t *journal, uint64_t size) 996 | { 997 | int err; 998 | vhd_context_t *vhd; 999 | uint64_t cur_secs, new_secs; 1000 | 1001 | vhd = &journal->vhd; 1002 | cur_secs = vhd->footer.curr_size >> VHD_SECTOR_SHIFT; 1003 | new_secs = size << (20 - VHD_SECTOR_SHIFT); 1004 | 1005 | if (cur_secs == new_secs) 1006 | return 0; 1007 | 1008 | err = vhd_get_header(vhd); 1009 | if (err) 1010 | return err; 1011 | 1012 | err = vhd_get_bat(vhd); 1013 | if (err) 1014 | return err; 1015 | 1016 | if (vhd_has_batmap(vhd)) { 1017 | err = vhd_get_batmap(vhd); 1018 | if (err) 1019 | return err; 1020 | } 1021 | 1022 | if (cur_secs > new_secs) 1023 | err = vhd_dynamic_shrink(journal, cur_secs - new_secs); 1024 | else 1025 | err = vhd_dynamic_grow(journal, new_secs - cur_secs); 1026 | 1027 | return err; 1028 | } 1029 | 1030 | static int 1031 | vhd_util_resize_check_creator(const char *name) 1032 | { 1033 | int err; 1034 | vhd_context_t vhd; 1035 | 1036 | err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_STRICT); 1037 | if (err) { 1038 | printf("error opening %s: %d\n", name, err); 1039 | return err; 1040 | } 1041 | 1042 | if (!vhd_creator_tapdisk(&vhd)) { 1043 | printf("%s not created by xen; resize not supported\n", name); 1044 | err = -EINVAL; 1045 | } 1046 | 1047 | vhd_close(&vhd); 1048 | return err; 1049 | } 1050 | 1051 | int 1052 | vhd_util_resize(int argc, char **argv) 1053 | { 1054 | char *name, *jname; 1055 | uint64_t size; 1056 | int c, err, jerr; 1057 | vhd_journal_t journal; 1058 | vhd_context_t *vhd; 1059 | 1060 | err = -EINVAL; 1061 | size = 0; 1062 | name = NULL; 1063 | jname = NULL; 1064 | 1065 | optind = 0; 1066 | while ((c = getopt(argc, argv, "n:j:s:h")) != -1) { 1067 | switch (c) { 1068 | case 'n': 1069 | name = optarg; 1070 | break; 1071 | case 'j': 1072 | jname = optarg; 1073 | break; 1074 | case 's': 1075 | err = 0; 1076 | size = strtoull(optarg, NULL, 10); 1077 | break; 1078 | case 'h': 1079 | default: 1080 | goto usage; 1081 | } 1082 | } 1083 | 1084 | if (err || !name || !jname || argc != optind) 1085 | goto usage; 1086 | 1087 | err = vhd_util_resize_check_creator(name); 1088 | if (err) 1089 | return err; 1090 | 1091 | libvhd_set_log_level(1); 1092 | err = vhd_journal_create(&journal, name, jname); 1093 | if (err) { 1094 | printf("creating journal failed: %d\n", err); 1095 | return err; 1096 | } 1097 | 1098 | vhd = &journal.vhd; 1099 | 1100 | err = vhd_get_footer(vhd); 1101 | if (err) 1102 | goto out; 1103 | 1104 | TEST_FAIL_AT(FAIL_RESIZE_BEGIN); 1105 | 1106 | if (vhd_type_dynamic(vhd)) 1107 | err = vhd_dynamic_resize(&journal, size); 1108 | else 1109 | err = vhd_fixed_resize(&journal, size); 1110 | 1111 | TEST_FAIL_AT(FAIL_RESIZE_END); 1112 | 1113 | out: 1114 | if (err) { 1115 | printf("resize failed: %d\n", err); 1116 | jerr = vhd_journal_revert(&journal); 1117 | } else 1118 | jerr = vhd_journal_commit(&journal); 1119 | 1120 | if (jerr) { 1121 | printf("closing journal failed: %d\n", jerr); 1122 | vhd_journal_close(&journal); 1123 | } else 1124 | vhd_journal_remove(&journal); 1125 | 1126 | return (err ? : jerr); 1127 | 1128 | usage: 1129 | printf("options: <-n name> <-j journal> <-s size (in MB)> [-h help]\n"); 1130 | return -EINVAL; 1131 | } 1132 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-revert.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | * Altering operations: 28 | * 29 | * 1. Change the parent pointer to another file. 30 | * 2. Change the size of the file containing the VHD image. This does NOT 31 | * affect the VHD disk capacity, only the physical size of the file containing 32 | * the VHD. Naturally, it is not possible to set the file size to be less than 33 | * the what VHD utilizes. 34 | * The operation doesn't actually change the file size, but it writes the 35 | * footer in the right location such that resizing the file (manually, as a 36 | * separate step) will produce the correct results. If the new file size is 37 | * greater than the current file size, the file must first be expanded and then 38 | * altered with this operation. If the new size is smaller than the current 39 | * size, the VHD must first be altered with this operation and then the file 40 | * must be shrunk. Failing to resize the file will result in a corrupted VHD. 41 | */ 42 | 43 | #include 44 | //#include 45 | #include 46 | //#include 47 | #include 48 | 49 | #include "libvhd.h" 50 | #include "libvhd-journal.h" 51 | 52 | int 53 | vhd_util_revert(int argc, char **argv) 54 | { 55 | char *name, *jname; 56 | vhd_journal_t journal; 57 | int c, err; 58 | 59 | name = NULL; 60 | jname = NULL; 61 | 62 | optind = 0; 63 | while ((c = getopt(argc, argv, "n:j:h")) != -1) { 64 | switch (c) { 65 | case 'n': 66 | name = optarg; 67 | break; 68 | case 'j': 69 | jname = optarg; 70 | break; 71 | case 'h': 72 | default: 73 | goto usage; 74 | } 75 | } 76 | 77 | if (!name || !jname || argc != optind) 78 | goto usage; 79 | 80 | libvhd_set_log_level(1); 81 | err = vhd_journal_open(&journal, name, jname); 82 | if (err) { 83 | printf("opening journal failed: %d\n", err); 84 | return err; 85 | } 86 | 87 | err = vhd_journal_revert(&journal); 88 | if (err) { 89 | printf("reverting journal failed: %d\n", err); 90 | vhd_journal_close(&journal); 91 | return err; 92 | } 93 | 94 | err = vhd_journal_remove(&journal); 95 | if (err) { 96 | printf("removing journal failed: %d\n", err); 97 | vhd_journal_close(&journal); 98 | return err; 99 | } 100 | 101 | return 0; 102 | 103 | usage: 104 | printf("options: <-n name> <-j journal> [-h help]\n"); 105 | return -EINVAL; 106 | } 107 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-set-field.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "libvhd.h" 34 | 35 | int 36 | vhd_util_set_field(int argc, char **argv) 37 | { 38 | long value; 39 | int err, c; 40 | off_t eof; 41 | vhd_context_t vhd; 42 | char *name, *field; 43 | 44 | err = -EINVAL; 45 | value = 0; 46 | name = NULL; 47 | field = NULL; 48 | 49 | if (!argc || !argv) 50 | goto usage; 51 | 52 | optind = 0; 53 | while ((c = getopt(argc, argv, "n:f:v:h")) != -1) { 54 | switch (c) { 55 | case 'n': 56 | name = optarg; 57 | break; 58 | case 'f': 59 | field = optarg; 60 | break; 61 | case 'v': 62 | err = 0; 63 | value = strtol(optarg, NULL, 10); 64 | break; 65 | case 'h': 66 | default: 67 | goto usage; 68 | } 69 | } 70 | 71 | if (!name || !field || optind != argc || err) 72 | goto usage; 73 | 74 | if (strnlen(field, 25) >= 25) { 75 | printf("invalid field\n"); 76 | goto usage; 77 | } 78 | 79 | if (strcmp(field, "hidden")) { 80 | printf("invalid field %s\n", field); 81 | goto usage; 82 | } 83 | 84 | if (value < 0 || value > 255) { 85 | printf("invalid value %ld\n", value); 86 | goto usage; 87 | } 88 | 89 | err = vhd_open(&vhd, name, VHD_OPEN_RDWR); 90 | if (err) { 91 | printf("error opening %s: %d\n", name, err); 92 | return err; 93 | } 94 | 95 | vhd.footer.hidden = (char)value; 96 | 97 | err = vhd_write_footer(&vhd, &vhd.footer); 98 | 99 | done: 100 | vhd_close(&vhd); 101 | return err; 102 | 103 | usage: 104 | printf("options: <-n name> <-f field> <-v value> [-h help]\n"); 105 | return -EINVAL; 106 | } 107 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util-snapshot.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "libvhd.h" 34 | 35 | static int 36 | vhd_util_find_snapshot_target(const char *name, char **result, int *parent_raw) 37 | { 38 | int i, err; 39 | char *target; 40 | vhd_context_t vhd; 41 | 42 | *parent_raw = 0; 43 | *result = NULL; 44 | 45 | target = strdup(name); 46 | if (!target) 47 | return -ENOMEM; 48 | 49 | for (;;) { 50 | err = vhd_open(&vhd, target, VHD_OPEN_RDONLY); 51 | if (err) 52 | return err; 53 | 54 | if (vhd.footer.type != HD_TYPE_DIFF) 55 | goto out; 56 | 57 | err = vhd_get_bat(&vhd); 58 | if (err) 59 | goto out; 60 | 61 | for (i = 0; i < vhd.bat.entries; i++) 62 | if (vhd.bat.bat[i] != DD_BLK_UNUSED) 63 | goto out; 64 | 65 | free(target); 66 | err = vhd_parent_locator_get(&vhd, &target); 67 | if (err) 68 | goto out; 69 | 70 | if (vhd_parent_raw(&vhd)) { 71 | *parent_raw = 1; 72 | goto out; 73 | } 74 | 75 | vhd_close(&vhd); 76 | } 77 | 78 | out: 79 | vhd_close(&vhd); 80 | if (err) 81 | free(target); 82 | else 83 | *result = target; 84 | 85 | return err; 86 | } 87 | 88 | static int 89 | vhd_util_check_depth(const char *name, int *depth) 90 | { 91 | int err; 92 | vhd_context_t vhd; 93 | 94 | err = vhd_open(&vhd, name, VHD_OPEN_RDONLY); 95 | if (err) 96 | return err; 97 | 98 | err = vhd_chain_depth(&vhd, depth); 99 | vhd_close(&vhd); 100 | 101 | return err; 102 | } 103 | 104 | int 105 | vhd_util_snapshot(int argc, char **argv) 106 | { 107 | vhd_flag_creat_t flags; 108 | int c, err, prt_raw, limit; 109 | char *name, *pname, *ppath, *backing; 110 | uint64_t size; 111 | vhd_context_t vhd; 112 | 113 | name = NULL; 114 | pname = NULL; 115 | ppath = NULL; 116 | backing = NULL; 117 | size = 0; 118 | flags = 0; 119 | limit = 0; 120 | 121 | if (!argc || !argv) { 122 | err = -EINVAL; 123 | goto usage; 124 | } 125 | 126 | optind = 0; 127 | while ((c = getopt(argc, argv, "n:p:l:mh")) != -1) { 128 | switch (c) { 129 | case 'n': 130 | name = optarg; 131 | break; 132 | case 'p': 133 | pname = optarg; 134 | break; 135 | case 'l': 136 | limit = strtol(optarg, NULL, 10); 137 | break; 138 | case 'm': 139 | vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW); 140 | break; 141 | case 'h': 142 | err = 0; 143 | goto usage; 144 | default: 145 | err = -EINVAL; 146 | goto usage; 147 | } 148 | } 149 | 150 | if (!name || !pname || optind != argc) { 151 | err = -EINVAL; 152 | goto usage; 153 | } 154 | 155 | ppath = realpath(pname, NULL); 156 | if (!ppath) 157 | return -errno; 158 | 159 | if (vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) { 160 | backing = strdup(ppath); 161 | if (!backing) { 162 | err = -ENOMEM; 163 | goto out; 164 | } 165 | } else { 166 | err = vhd_util_find_snapshot_target(ppath, &backing, &prt_raw); 167 | if (err) { 168 | backing = NULL; 169 | goto out; 170 | } 171 | 172 | /* 173 | * if the sizes of the parent chain are non-uniform, we need to 174 | * pick the right size: that of the supplied parent 175 | */ 176 | if (strcmp(ppath, backing)) { 177 | err = vhd_open(&vhd, ppath, VHD_OPEN_RDONLY); 178 | if (err) 179 | goto out; 180 | size = vhd.footer.curr_size; 181 | vhd_close(&vhd); 182 | } 183 | 184 | if (prt_raw) 185 | vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW); 186 | } 187 | 188 | if (limit && !vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) { 189 | int depth; 190 | 191 | err = vhd_util_check_depth(backing, &depth); 192 | if (err) 193 | printf("error checking snapshot depth: %d\n", err); 194 | else if (depth + 1 > limit) { 195 | err = -ENOSPC; 196 | printf("snapshot depth exceeded: " 197 | "current depth: %d, limit: %d\n", depth, limit); 198 | } 199 | 200 | if (err) 201 | goto out; 202 | } 203 | 204 | err = vhd_snapshot(name, size, backing, flags); 205 | 206 | out: 207 | free(ppath); 208 | free(backing); 209 | 210 | return err; 211 | 212 | usage: 213 | printf("options: <-n name> <-p parent name> [-l snapshot depth limit]" 214 | " [-m parent_is_raw] [-h help]\n"); 215 | return err; 216 | } 217 | -------------------------------------------------------------------------------- /tools/vhd-util/vhd-util.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2008, XenSource Inc. 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of XenSource Inc. nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "libvhd.h" 33 | #include "vhd-util.h" 34 | 35 | #if 1 36 | #define DFPRINTF(_f, _a...) fprintf(stdout, _f , ##_a) 37 | #else 38 | #define DFPRINTF(_f, _a...) ((void)0) 39 | #endif 40 | 41 | typedef int (*vhd_util_func_t) (int, char **); 42 | 43 | struct command { 44 | char *name; 45 | vhd_util_func_t func; 46 | }; 47 | 48 | struct command commands[] = { 49 | { .name = "create", .func = vhd_util_create }, 50 | { .name = "snapshot", .func = vhd_util_snapshot }, 51 | { .name = "query", .func = vhd_util_query }, 52 | { .name = "read", .func = vhd_util_read }, 53 | { .name = "set", .func = vhd_util_set_field }, 54 | { .name = "repair", .func = vhd_util_repair }, 55 | { .name = "resize", .func = vhd_util_resize }, 56 | { .name = "fill", .func = vhd_util_fill }, 57 | { .name = "coalesce", .func = vhd_util_coalesce }, 58 | { .name = "modify", .func = vhd_util_modify }, 59 | { .name = "scan", .func = vhd_util_scan }, 60 | { .name = "check", .func = vhd_util_check }, 61 | { .name = "revert", .func = vhd_util_revert }, 62 | }; 63 | 64 | #define print_commands() \ 65 | do { \ 66 | int i, n; \ 67 | n = sizeof(commands) / sizeof(struct command); \ 68 | printf("COMMAND := { "); \ 69 | printf("%s", commands[0].name); \ 70 | for (i = 1; i < n; i++) \ 71 | printf(" | %s", commands[i].name); \ 72 | printf(" }\n"); \ 73 | } while (0) 74 | 75 | TEST_FAIL_EXTERN_VARS; 76 | 77 | void 78 | help(void) 79 | { 80 | printf("usage: vhd-util COMMAND [OPTIONS]\n"); 81 | print_commands(); 82 | exit(0); 83 | } 84 | 85 | struct command * 86 | get_command(char *command) 87 | { 88 | int i, n; 89 | 90 | if (strnlen(command, 25) >= 25) 91 | return NULL; 92 | 93 | n = sizeof(commands) / sizeof (struct command); 94 | 95 | for (i = 0; i < n; i++) 96 | if (!strcmp(command, commands[i].name)) 97 | return &commands[i]; 98 | 99 | return NULL; 100 | } 101 | 102 | int 103 | main(int argc, char *argv[]) 104 | { 105 | char **cargv; 106 | struct command *cmd; 107 | int cargc, i, cnt, ret; 108 | 109 | #ifdef CORE_DUMP 110 | #include 111 | struct rlimit rlim; 112 | rlim.rlim_cur = RLIM_INFINITY; 113 | rlim.rlim_max = RLIM_INFINITY; 114 | if (setrlimit(RLIMIT_CORE, &rlim) < 0) 115 | fprintf(stderr, "setrlimit failed: %d\n", errno); 116 | #endif 117 | 118 | ret = 0; 119 | 120 | if (argc < 2) 121 | help(); 122 | 123 | cargc = argc - 1; 124 | cmd = get_command(argv[1]); 125 | if (!cmd) { 126 | fprintf(stderr, "invalid COMMAND %s\n", argv[1]); 127 | help(); 128 | } 129 | 130 | cargv = malloc(sizeof(char *) * cargc); 131 | if (!cargv) 132 | exit(ENOMEM); 133 | 134 | cnt = 1; 135 | cargv[0] = cmd->name; 136 | for (i = 1; i < cargc; i++) { 137 | char *arg = argv[i + (argc - cargc)]; 138 | 139 | if (!strcmp(arg, "--debug")) { 140 | libvhd_set_log_level(1); 141 | continue; 142 | } 143 | 144 | cargv[cnt++] = arg; 145 | } 146 | 147 | #ifdef ENABLE_FAILURE_TESTING 148 | for (i = 0; i < NUM_FAIL_TESTS; i++) { 149 | TEST_FAIL[i] = 0; 150 | if (getenv(ENV_VAR_FAIL[i])) 151 | TEST_FAIL[i] = 1; 152 | } 153 | #endif // ENABLE_FAILURE_TESTING 154 | 155 | ret = cmd->func(cnt, cargv); 156 | 157 | free(cargv); 158 | 159 | return (ret >= 0 ? ret : -ret); 160 | } 161 | --------------------------------------------------------------------------------